Merge "Use a mock PermissionSettings for PMSettingsTest"
diff --git a/Android.bp b/Android.bp
index 9e838b3..121decb 100644
--- a/Android.bp
+++ b/Android.bp
@@ -162,49 +162,54 @@
     path: "wifi/java",
 }
 
-framework_srcs = [
-    // Java/AIDL sources under frameworks/base
-    ":framework-core-sources",
-    ":framework-drm-sources",
-    ":framework-graphics-sources",
-    ":framework-keystore-sources",
-    ":framework-location-sources",
-    ":framework-lowpan-sources",
-    ":framework-media-sources",
-    ":framework-mca-effect-sources",
-    ":framework-mca-filterfw-sources",
-    ":framework-mca-filterpacks-sources",
-    ":framework-opengl-sources",
-    ":framework-rs-sources",
-    ":framework-sax-sources",
-    ":framework-telecomm-sources",
-    ":framework-telephony-sources",
-    ":framework-wifi-sources",
-    ":PacProcessor-aidl-sources",
-    ":ProxyHandler-aidl-sources",
+filegroup {
+    name: "framework-srcs",
+    srcs: [
+        // Java/AIDL sources under frameworks/base
+        ":framework-core-sources",
+        ":framework-drm-sources",
+        ":framework-graphics-sources",
+        ":framework-keystore-sources",
+        ":framework-location-sources",
+        ":framework-lowpan-sources",
+        ":framework-media-sources",
+        ":framework-mca-effect-sources",
+        ":framework-mca-filterfw-sources",
+        ":framework-mca-filterpacks-sources",
+        ":framework-opengl-sources",
+        ":framework-rs-sources",
+        ":framework-sax-sources",
+        ":framework-telecomm-sources",
+        ":framework-telephony-sources",
+        ":framework-wifi-sources",
+        ":PacProcessor-aidl-sources",
+        ":ProxyHandler-aidl-sources",
 
-    // AIDL sources from external directories
-    ":dumpstate_aidl",
-    ":framework_native_aidl",
-    ":gatekeeper_aidl",
-    ":gsiservice_aidl",
-    ":incidentcompanion_aidl",
-    ":installd_aidl",
-    ":keystore_aidl",
-    ":libaudioclient_aidl",
-    ":libbinder_aidl",
-    ":libbluetooth-binder-aidl",
-    ":libcamera_client_aidl",
-    ":libcamera_client_framework_aidl",
-    ":libupdate_engine_aidl",
-    ":storaged_aidl",
-    ":vold_aidl",
+        // AIDL sources from external directories
+        ":dumpstate_aidl",
+        ":framework_native_aidl",
+        ":gatekeeper_aidl",
+        ":gsiservice_aidl",
+        ":incidentcompanion_aidl",
+        ":installd_aidl",
+        ":keystore_aidl",
+        ":libaudioclient_aidl",
+        ":libbinder_aidl",
+        ":libbluetooth-binder-aidl",
+        ":libcamera_client_aidl",
+        ":libcamera_client_framework_aidl",
+        ":libupdate_engine_aidl",
+        ":storaged_aidl",
+        ":vold_aidl",
 
-    // etc.
-    "core/java/**/*.logtags",
-    ":framework-javastream-protos",
-    ":framework-statslog-gen",
-]
+        // For the generated R.java and Manifest.java
+        ":framework-res{.aapt.srcjar}",
+
+        // etc.
+        ":framework-javastream-protos",
+        ":framework-statslog-gen",
+    ],
+}
 
 java_defaults {
     name: "framework-aidl-export-defaults",
@@ -231,32 +236,11 @@
     },
 }
 
-java_defaults {
-    name: "framework-defaults",
-    defaults: ["framework-aidl-export-defaults"],
-    installable: true,
-
-    srcs: framework_srcs,
-
-    aidl: {
-        generate_get_transaction_name: true,
-    },
-
-    exclude_srcs: [
-        // See comment on framework-atb-backward-compatibility module below
-        "core/java/android/content/pm/AndroidTestBaseUpdater.java",
-    ],
-
-    sdk_version: "core_platform",
-    libs: [
-        "ext",
-        "updatable_media_stubs",
-    ],
-
-    jarjar_rules: ":framework-jarjar-rules",
-
+// Collection of classes that are generated from non-Java files that are not listed in
+// framework_srcs. These have no or very limited dependency to the framework.
+java_library {
+    name: "framework-internal-utils",
     static_libs: [
-        "mimemap",
         "apex_aidl_interface-java",
         "suspend_control_aidl_interface-java",
         "framework-protos",
@@ -290,6 +274,38 @@
         "com.android.sysprop.apex",
         "PlatformProperties",
     ],
+    sdk_version: "core_platform",
+    installable: false,
+}
+
+java_defaults {
+    name: "framework-defaults",
+    defaults: ["framework-aidl-export-defaults"],
+    installable: true,
+
+    srcs: [
+        ":framework-srcs",
+        "core/java/**/*.logtags",
+    ],
+
+    aidl: {
+        generate_get_transaction_name: true,
+    },
+
+    exclude_srcs: [
+        // See comment on framework-atb-backward-compatibility module below
+        "core/java/android/content/pm/AndroidTestBaseUpdater.java",
+    ],
+
+    sdk_version: "core_platform",
+    libs: [
+        "ext",
+        "updatable_media_stubs",
+    ],
+
+    jarjar_rules: ":framework-jarjar-rules",
+
+    static_libs: ["framework-internal-utils"],
 
     required: [
         // TODO: remove gps_debug when the build system propagates "required" properly.
@@ -374,7 +390,6 @@
 
 platform_compat_config {
     name: "framework-platform-compat-config",
-    prefix: "framework",
     src: ":framework-annotation-proc",
 }
 
@@ -760,7 +775,7 @@
     ],
 }
 
-// TODO: Don't rely on this list once droiddoc can take a list of packages to document
+// TODO: Don't rely on this list by switching package.html into package-info.java
 frameworks_base_subdirs = [
     "core/java",
     "graphics/java",
@@ -780,13 +795,6 @@
     "rs/java",
 ]
 
-packages_to_document = [
-    "android",
-    "javax/microedition/khronos",
-    "org/apache/http/conn",
-    "org/apache/http/params",
-]
-
 // Make the api/current.txt file available for use by modules in other
 // directories.
 filegroup {
@@ -879,17 +887,17 @@
 stubs_defaults {
     name: "framework-doc-stubs-default",
     srcs: [
+        ":framework-srcs",
+        "core/java/**/*.logtags",
         "test-base/src/**/*.java",
         ":opt-telephony-srcs",
         ":opt-net-voip-srcs",
         ":core_public_api_files",
-        ":updatable-media-srcs-without-aidls",
+        ":updatable-media-srcs",
         "test-mock/src/**/*.java",
         "test-runner/src/**/*.java",
         ":jobscheduler-framework-source",
     ],
-    srcs_lib: "framework-minus-apex",
-    srcs_lib_whitelist_pkgs: packages_to_document,
     libs: framework_docs_only_libs,
     local_sourcepaths: frameworks_base_subdirs,
     create_doc_stubs: true,
@@ -936,17 +944,23 @@
     create_stubs: false,
 }
 
+doc_defaults {
+    name: "framework-dokka-docs-default",
+    create_stubs: false,
+}
+
 stubs_defaults {
     name: "metalava-api-stubs-default",
     srcs: [
+        ":framework-srcs",
+        "core/java/**/*.logtags",
         ":opt-telephony-srcs",
         ":opt-net-voip-srcs",
         ":core_public_api_files",
-        ":updatable-media-srcs-without-aidls",
+        ":updatable-media-srcs",
         ":jobscheduler-framework-source",
     ],
-    srcs_lib: "framework-minus-apex",
-    srcs_lib_whitelist_pkgs: packages_to_document,
+    libs: ["framework-internal-utils"],
     local_sourcepaths: frameworks_base_subdirs,
     installable: false,
     annotations_enabled: true,
@@ -960,6 +974,7 @@
         "sdk-dir",
         "api-versions-jars-dir",
     ],
+    sdk_version: "core_platform",
 }
 
 droidstubs {
@@ -1109,7 +1124,7 @@
 }
 
 droiddoc {
-    name: "ds-docs",
+    name: "ds-docs-java",
     defaults: ["framework-docs-default"],
     srcs: [
         ":framework-doc-stubs",
@@ -1138,6 +1153,58 @@
 }
 
 droiddoc {
+    name: "ds-docs-kt",
+    defaults: ["framework-dokka-docs-default"],
+    srcs: [
+        ":framework-doc-stubs",
+    ],
+    args: "-noJdkLink -links https://kotlinlang.org/api/latest/jvm/stdlib/^external/dokka/package-list " +
+    "-noStdlibLink",
+    proofread_file: "ds-dokka-proofread.txt",
+    dokka_enabled: true,
+}
+
+java_genrule {
+    name: "ds-docs",
+    tools: [
+        "zip2zip",
+        "merge_zips",
+    ],
+    srcs: [
+        ":ds-docs-java{.docs.zip}",
+        ":ds-docs-kt{.docs.zip}",
+    ],
+    out: ["ds-docs.zip"],
+    dist: {
+        targets: ["docs"],
+    },
+    cmd: "$(location zip2zip) -i $(location :ds-docs-kt{.docs.zip}) -o $(genDir)/ds-docs-kt-moved.zip **/*:en/reference/kotlin && " +
+         "$(location merge_zips) $(out) $(location :ds-docs-java{.docs.zip}) $(genDir)/ds-docs-kt-moved.zip",
+}
+
+java_genrule {
+    name: "ds-docs-switched",
+    tools: [
+        "switcher4",
+        "soong_zip",
+    ],
+    srcs: [
+        ":ds-docs-java{.docs.zip}",
+        ":ds-docs-kt{.docs.zip}",
+    ],
+    out: ["ds-docs-switched.zip"],
+    dist: {
+        targets: ["docs"],
+    },
+    cmd: "unzip $(location :ds-docs-java{.docs.zip}) -d $(genDir) && " +
+         "unzip $(location :ds-docs-kt{.docs.zip}) -d $(genDir)/en/reference/kotlin && " +
+         "SWITCHER=$$(cd $$(dirname $(location switcher4)) && pwd)/$$(basename $(location switcher4)) && " +
+         "(cd $(genDir)/en/reference && $$SWITCHER --work platform) && " +
+         "$(location soong_zip) -o $(out) -C $(genDir) -D $(genDir)",
+}
+
+
+droiddoc {
     name: "ds-static-docs",
     defaults: ["framework-docs-default"],
     srcs: [
@@ -1271,6 +1338,7 @@
         ":openjdk_java_files",
         ":opt-telephony-common-srcs",
     ],
+
     arg_files: [
         "core/res/AndroidManifest.xml",
     ],
@@ -1405,7 +1473,7 @@
 // annotations to private apis
 aidl_mapping {
     name: "framework-aidl-mappings",
-    srcs: framework_srcs,
+    srcs: [":framework-srcs"],
     output: "framework-aidl-mappings.txt",
 }
 
diff --git a/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl b/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl
index aa255bf..9d5becb 100644
--- a/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl
+++ b/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl
@@ -16,7 +16,6 @@
 
 package android.os;
 
-import android.os.IMaintenanceActivityListener;
 import android.os.UserHandle;
 
 /** @hide */
@@ -44,8 +43,6 @@
     long addPowerSaveTempWhitelistAppForMms(String name, int userId, String reason);
     long addPowerSaveTempWhitelistAppForSms(String name, int userId, String reason);
     void exitIdle(String reason);
-    boolean registerMaintenanceActivityListener(IMaintenanceActivityListener listener);
-    void unregisterMaintenanceActivityListener(IMaintenanceActivityListener listener);
     int setPreIdleTimeoutMode(int Mode);
     void resetPreIdleTimeoutMode();
 }
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index 62930b0..d0e38b4 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -51,14 +51,12 @@
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.IDeviceIdleController;
-import android.os.IMaintenanceActivityListener;
 import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.PowerManager.ServiceType;
 import android.os.PowerManagerInternal;
 import android.os.Process;
-import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
@@ -448,7 +446,6 @@
                                                        // down.
     private boolean mJobsActive;
     private boolean mAlarmsActive;
-    private boolean mReportedMaintenanceActivity;
 
     /* Factor to apply to INACTIVE_TIMEOUT and IDLE_AFTER_INACTIVE_TIMEOUT in order to enter
      * STATE_IDLE faster or slower. Don't apply this to SENSING_TIMEOUT or LOCATING_TIMEOUT because:
@@ -463,9 +460,6 @@
 
     public final AtomicFile mConfigFile;
 
-    private final RemoteCallbackList<IMaintenanceActivityListener> mMaintenanceActivityListeners =
-            new RemoteCallbackList<IMaintenanceActivityListener>();
-
     /**
      * Package names the system has white-listed to opt out of power save restrictions,
      * except for device idle mode.
@@ -1309,7 +1303,6 @@
     private static final int MSG_REPORT_IDLE_OFF = 4;
     private static final int MSG_REPORT_ACTIVE = 5;
     private static final int MSG_TEMP_APP_WHITELIST_TIMEOUT = 6;
-    private static final int MSG_REPORT_MAINTENANCE_ACTIVITY = 7;
     private static final int MSG_FINISH_IDLE_OP = 8;
     private static final int MSG_REPORT_TEMP_APP_WHITELIST_CHANGED = 9;
     private static final int MSG_SEND_CONSTRAINT_MONITORING = 10;
@@ -1410,22 +1403,6 @@
                     int appId = msg.arg1;
                     checkTempAppWhitelistTimeout(appId);
                 } break;
-                case MSG_REPORT_MAINTENANCE_ACTIVITY: {
-                    // TODO: What is keeping the device awake at this point? Does it need to be?
-                    boolean active = (msg.arg1 == 1);
-                    final int size = mMaintenanceActivityListeners.beginBroadcast();
-                    try {
-                        for (int i = 0; i < size; i++) {
-                            try {
-                                mMaintenanceActivityListeners.getBroadcastItem(i)
-                                        .onMaintenanceActivityChanged(active);
-                            } catch (RemoteException ignored) {
-                            }
-                        }
-                    } finally {
-                        mMaintenanceActivityListeners.finishBroadcast();
-                    }
-                } break;
                 case MSG_FINISH_IDLE_OP: {
                     // mActiveIdleWakeLock is held at this point
                     decActiveIdleOps();
@@ -1594,16 +1571,6 @@
             }
         }
 
-        @Override public boolean registerMaintenanceActivityListener(
-                IMaintenanceActivityListener listener) {
-            return DeviceIdleController.this.registerMaintenanceActivityListener(listener);
-        }
-
-        @Override public void unregisterMaintenanceActivityListener(
-                IMaintenanceActivityListener listener) {
-            DeviceIdleController.this.unregisterMaintenanceActivityListener(listener);
-        }
-
         @Override public int setPreIdleTimeoutMode(int mode) {
             getContext().enforceCallingOrSelfPermission(Manifest.permission.DEVICE_POWER,
                     null);
@@ -3131,7 +3098,6 @@
     void setJobsActive(boolean active) {
         synchronized (this) {
             mJobsActive = active;
-            reportMaintenanceActivityIfNeededLocked();
             if (!active) {
                 exitMaintenanceEarlyIfNeededLocked();
             }
@@ -3147,19 +3113,6 @@
         }
     }
 
-    boolean registerMaintenanceActivityListener(IMaintenanceActivityListener listener) {
-        synchronized (this) {
-            mMaintenanceActivityListeners.register(listener);
-            return mReportedMaintenanceActivity;
-        }
-    }
-
-    void unregisterMaintenanceActivityListener(IMaintenanceActivityListener listener) {
-        synchronized (this) {
-            mMaintenanceActivityListeners.unregister(listener);
-        }
-    }
-
     @VisibleForTesting
     int setPreIdleTimeoutMode(int mode) {
         return setPreIdleTimeoutFactor(getPreIdleTimeoutByMode(mode));
@@ -3281,17 +3234,6 @@
         }
     }
 
-    void reportMaintenanceActivityIfNeededLocked() {
-        boolean active = mJobsActive;
-        if (active == mReportedMaintenanceActivity) {
-            return;
-        }
-        mReportedMaintenanceActivity = active;
-        Message msg = mHandler.obtainMessage(MSG_REPORT_MAINTENANCE_ACTIVITY,
-                mReportedMaintenanceActivity ? 1 : 0, 0);
-        mHandler.sendMessage(msg);
-    }
-
     @VisibleForTesting
     long getNextAlarmTime() {
         return mNextAlarmTime;
diff --git a/apex/statsd/Android.bp b/apex/statsd/Android.bp
new file mode 100644
index 0000000..d76a40e
--- /dev/null
+++ b/apex/statsd/Android.bp
@@ -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.
+
+apex {
+    name: "com.android.os.statsd",
+
+    manifest: "apex_manifest.json",
+
+    // optional. if unspecified, a default one is auto-generated
+    //androidManifest: "AndroidManifest.xml",
+
+    // libc.so and libcutils.so are included in the apex
+    // native_shared_libs: ["libc", "libcutils"],
+    // binaries: ["vold"],
+    // java_libs: ["core-all"],
+    // prebuilts: ["my_prebuilt"],
+
+    compile_multilib: "both",
+
+    key: "com.android.os.statsd.key",
+    certificate: ":com.android.os.statsd.certificate",
+}
+
+apex_key {
+    name: "com.android.os.statsd.key",
+    public_key: "com.android.os.statsd.avbpubkey",
+    private_key: "com.android.os.statsd.pem",
+}
+
+android_app_certificate {
+    name: "com.android.os.statsd.certificate",
+    // This will use com.android.os.statsd.x509.pem (the cert) and
+    // com.android.os.statsd.pk8 (the private key)
+    certificate: "com.android.os.statsd",
+}
diff --git a/apex/statsd/apex_manifest.json b/apex/statsd/apex_manifest.json
new file mode 100644
index 0000000..0c0ad86
--- /dev/null
+++ b/apex/statsd/apex_manifest.json
@@ -0,0 +1,5 @@
+{
+  "name": "com.android.os.statsd",
+  "version": 1
+}
+
diff --git a/apex/statsd/com.android.os.statsd.avbpubkey b/apex/statsd/com.android.os.statsd.avbpubkey
new file mode 100644
index 0000000..d78af8b
--- /dev/null
+++ b/apex/statsd/com.android.os.statsd.avbpubkey
Binary files differ
diff --git a/apex/statsd/com.android.os.statsd.pem b/apex/statsd/com.android.os.statsd.pem
new file mode 100644
index 0000000..558e17f
--- /dev/null
+++ b/apex/statsd/com.android.os.statsd.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKgIBAAKCAgEA893bbpkivKEiNgfknYBSlzC0csaKU/ddBm5Pb4ZFuab+LQSR
+9DDc5JrsmxyrsrvuwL/zAtMbkyYWzEiUxJtx/w0bw8rC90GoPRSCmxyI0ZK8FuPy
+IAQ7UeNfTWZ485mAUaTSasGIfQ3DY4F0P+aUSijeG3NUY02nALHDMqJX7lXR+mL1
+DUYDg05KB0jxQwlYqBeujTPPiAzEqm3PlBoHuan8/qgK2wdQMTVg/fieUD3lupmV
+Wj2dRZgqfBPA16ZbV4Uo0j0bZSf+fQLiXlU2VJGb5i/FQfjLqMKGABDI0MgK7Sc2
+m4ySpV4g4XKDv/vw6Dw4kwWC7mATEVAkH+q6V7uiZeN6a7w30UMtPI8fPaUvAP3L
+VBjCBIv/3m+CKkWcNxOZ3sQBQl5bS05dxcfiVsBvBLYbvQgC+Wy0Sc3b+1pXFT/E
+uAsbZ4CyVsi1+PAdx3h5e2QAyNCXgZDOcvTUyxY6JLTE0LOVHmI4fJEujBex//Oz
+PCRHvC8K+KiljyQWf/NYrLSD3QGYAjVMtQh7yu2yhzWzgBUxyhuv3rY4ATXsN3bJ
+wW4w7/L/RSLSW5+lp/NoJOD9utbsKTyGMHOY6K8JLOmhv3ORoAEmLYlFTI+FqBi9
+AH1HQEKCyh8Z/bYHLUzGWl6FqAMtcnuintv40BbKyt0/D1ItdbSNKmOZ5rkCAwEA
+AQKCAgAY7ll8mRNADYkd1Pi+UVwgMM6B3WJO6z8LZUOhtyxxqmzZ1VnGiShMBrqh
+sPCsuSHTeswxQbvT81TpVZI/91RUKtbn0VbVSFUWyX4AtY4XPtUT0gHy2/vkh0Y6
+93ruDIdd0Wfhmh+GCV4sUhO8ZKpMWpk6XTQHYuzr2UCHcKlkqElrO6qpzLqXNe3D
+iOWBYPc7WBB0RxO0aPnCIq/SCEc55/MBZdSWR80e+sILtNsagPl3djQaoanub3wI
+a0yPv2YfMHHX7H9cfBY8WYsi8bs4MhqqEcAs2m6XtitU3mJpVcooLJYcmOZ1GYZr
+BfYKLouWcnGmNi4IiLHqVzMaQDkEhAZsRaAXCkoVVrFBedLlmLPpiUIQlINF4vxe
+3IcekTKWyMzkU6h+K8T15MU5mLSqeL2Gji1JIwKJno51FZ9uc++pUJVtfYQmNny8
+8RKvQ1hv/S5yLQKgN+VkNbaWlUoMP73dtUe3m/At71/2Dj7xB0KtcgT1lEMrM1GR
+oynJAJLz/d0n5RUUREwkZZMcA4fQVC7Db6vpK69jPiQMShpZ3JKCEjfYLUuN0slt
+FPhjiR175E0vTRuLoIj4kXNwLLswH0c9zqrKM2S92SCxAV3E4JJGKhUZalvT9s1g
+LrPhMCl6CsOES98T87d3RyAIK0iVRCnRUG3bc+8rzyRd4fzkAQKCAQEA/UjmCSm3
+H46t/1w7YBZPew7SFQOAJe81iDzbonc3fNPD2R8lxtD3MwdvrQ5f9fhT4+uveWNr
+dyBX7ppnissyM3LZRN+7BdeIVVeIPVen6Ou9W2i7q18ZoQx9IpRcZEw5tGJFZaGx
+EmyPN4i1K0ccUkGbBvbXXQ/tcG3wElRpBAc5/TQ8vrpUgHll2/MbYhowx6P9uHv5
+thoyG98X+7Fbg8ikzw5GtyuedXfyX1CpJ7yUQVS2PEaOMXOkZdx2bbWRAYYCpsqB
+dMmjs2PsFhZHu6CpLhlocHbfUiRztCUCaMZJPQXFSVmy8QDMvZEdVLvad9Poi8ny
+lmHVRgxaNbAtIQKCAQEA9nscqRaaO7hIX9bOUxcDbI0486Ws4H0hAFApIN+6/LP4
+hkxey3xWArTYWrvSG1d5GkJAdn99ayWzo2PevmJlrhIJiO1QqYBAk+87cnhwSCmB
+kb0sGkNWcc/xNRy7eqdhyCmVhaUnIbORee+cD6qiu/l2BAclTf2ZARFOGXjhQkvt
+cDbc/9ZR467ceXbiTIU34Be4xnNAY1mo59jvwl9eqxgpefYTqPhcZ7OmlDli77Hd
+XuRfuxLZCscv7A9M5Enc2zwOEP5VwRNwYzYtMm2Yh9CQZxNWC7JVh1Gw5MPFzsGl
+sgEdb4WGneN6PPLQHK7NF0f7wYSNnF0i3XSME9MumQKCAQEA0qMbWydr+TyJC0LC
+xigHtUkgAQXGPsXuePxTk4sdhBwAVcKHgg4qZi+a+gpoV4BLE9LfPU4nAwzM08to
+rI5Lk2nBsnt1Z2hVItQGoy0QoK3b7fbti5ktETf3oRhMtcSGgLLxD5ImVjId8Isq
+T3F15hpVOLdzZxtl1Qg4jKXSJ91yplYY5mzC9Yz/3qkQbsdlJcIFsLS5eG3UmkUw
+Bsr6VmA4X1F6Eb6eqwYzdHz6D+fOS36NhxcODaYkY+myO46xptixv8/NVTiTgQ5q
+OfwRb8Iur/3FUzIoioFyD7Bvjn7ITY1NArEsFS0bF9Nk1yDakKiUThyGN/Xojbac
+FuYKwQKCAQEAxOWJ+qU8phJLdowBHC0ZJiEWasRhep9auoZOpJ01IWOfV6EwZLs5
+dkYDQ1Agwoi5DDn6hu7HQM3IV/CS4mF2OnzcMw7ozc7PR53nTkVZ5LuLbuHAlmZO
+avKjDDucpJmLqjtV34IT5X8t6kt3zqgQAbuBBCy1Jz07ebfaPMzsnWpMDcU1/AW4
+OvrX0wweMOSGwzQP/i/ZMsRQAo2w0gQfeuv9Thk+kU99ebXwjx3co//hCEnFE4s1
+6L8/0AJU+VTr4hJyZi7WUDt4HzkLF+qm22/Hux+eMA/Q9R1UAxtFLCpTdAQiAJGY
+/Q3X+1I434DgAwYU3f1Gpq9cB65vq/KamQKCAQEAjIub5wde/ttHlLALvnOXrbqe
+nUIfWHExMzhul/rkr8fFEJwij2nZUuN2EWUGzBWQQoNXw5QKHLZyPsyFUOa/P2BS
+osnffAa+sumL4k36E71xFdTVV5ExyTXZVB49sPmUpivP9gEucFFqDHKjGsF45dBF
++DZdykLUIv+/jQUzXGkZ5Wv/r52YUNho4EZdwnlJ2so7cxnsYnjW+c1nlp17tkq5
+DfwktkeD9iFzlaZ66vLoO44luaBm+lC3xM2sHinOTwbk0gvhJAIoLfkOYhpmGc8A
+4W/E1OHfVz6xqVDsMBFhRbQpHNkf8XZNqkIoqHVMTaMOJJlM+lb0+A9B8Bm/XA==
+-----END RSA PRIVATE KEY-----
diff --git a/apex/statsd/com.android.os.statsd.pk8 b/apex/statsd/com.android.os.statsd.pk8
new file mode 100644
index 0000000..49910f8
--- /dev/null
+++ b/apex/statsd/com.android.os.statsd.pk8
Binary files differ
diff --git a/apex/statsd/com.android.os.statsd.x509.pem b/apex/statsd/com.android.os.statsd.x509.pem
new file mode 100644
index 0000000..e7b16b2
--- /dev/null
+++ b/apex/statsd/com.android.os.statsd.x509.pem
@@ -0,0 +1,30 @@
+-----BEGIN CERTIFICATE-----
+MIIFDTCCAvWgAwIBAgIUCnta1LAl5fMMLLQx//4zWz9A2A8wDQYJKoZIhvcNAQEL
+BQAwFTETMBEGA1UECgwKR29vZ2xlIExMQzAgFw0xOTA4MTIyMjM5MzBaGA80NzU3
+MDcwODIyMzkzMFowFTETMBEGA1UECgwKR29vZ2xlIExMQzCCAiIwDQYJKoZIhvcN
+AQEBBQADggIPADCCAgoCggIBAOranWZ19jkXCF9WIlXv01tUUvLKMHWKV7X9Earw
+cL7/aax0pFbNJutgyBUiOszbR+0T7quZxz6jACu+6y7iaMJnvMluZsfTi+p2UvQt
+y6Ql7ZUOQ7bVluCFIW5hZ+8d9RrLmZdvX1r4YfF6HufDBkAbj+os+y6407OezJAV
+8EATpemc9gsCC4RJZpwzTs1RUXMD4UoNrLZAE8+7iaJZeBxmz0MAPj92pYc9M7/d
+xInzYvOR08/uEpHt8jlMdVgSQS/FaRlIOIqcGBk3cjkjDlpVATQ4Hyjy+IPQPjTD
+bJUmDJiYeBCyY/pYZQvTQjl8s+fvykTsF9Lfb+E+PhZ0+N8pRi7sUSpisZHSiqaN
+W3oxYWc0YQSuzygHHog8HH/azHX5L805g/+Rwfb/cUF9eJgjq0vrkFnsz4UKgKNV
+hHL90mfqpbc2UvJ8VY8BvIjbsHQ77LrBKlqI9VMPorttpTOuwHHJPKsyN972F0Ul
+lRB6CwFE8csVGWXoNaDZWBv7xTDdbdirmlKDNueg9pw6ksYV2Is9Dv8PxmsZvb+4
+oftC/hb4X1Pudn01PPs9Tx44CwHuVLENUwlDEVzG5zNetsv9kAuCYt3VRVF+NYqj
+NAfLbxCKLe25wGzJrZUEJ1YrYIjpUbfwnttEad/9Pu13DAS7HZwn5vwqEKB/1LlT
+NSUXAgMBAAGjUzBRMB0GA1UdDgQWBBSKElkhJSbzgh8+iysye8SrkmJ62DAfBgNV
+HSMEGDAWgBSKElkhJSbzgh8+iysye8SrkmJ62DAPBgNVHRMBAf8EBTADAQH/MA0G
+CSqGSIb3DQEBCwUAA4ICAQANFGnc2wJBrFbh2nzhl06g4TjPKGRCw365vZ1A3T9O
+jXP0lToHDxB33TpKk6d7zszR1uPphQQxgzhSVZB/jx8q4kWSSoKoF9Dlx7h8rAt+
+2TM5DaBvxrwu5mqOALwQuF81wap1Pl2L2fFHvygCm8b+Ci4iS5vcr0axNnp1rK1b
+vUtRWY4mfxTjJYcgeCVUGskqTb+cCxQZ6Icno6VTKajT1FybRmD3KZJaUuLbNEN+
+IE4nGTMG2WZ5Hl2vR8JJp1sYYn8T3ElMAb0MSNFkqsfI+tToEwGsuJDgYEdtEnzf
+lTycQvn5NhrIZRRN3pqSyWpAU7p9mmyTK0PHMz2D/Rtfb7lE692vXzxCmZND51mc
+YXCCoanV6eZZ7Sbqzh60+5QV38hgFBst5l8CcFaWWSFK9nBWdzS5lhs9lmQ4aiYd
+IE0qsNZgMob+TTP1VW39hu4EDjNmOrKfimM9J2tcPZ5QP01DgETPvAsB7vn2Xz9J
+HGt5ntiSV4W2izDP8viQ1M5NvfdBaUhcnNsE6/sxfU0USRs2hrEp1oiqrv4p6V0P
+qOt7C2/YtJzkrxfsHZAxBUSRHa7LwtzgeiJDUivHn94VnAzSAH8MLx6CzDPQ8HWN
+NiZFxTKfMVyjEmbQ2PalHWB8pWtpdEh7X4rzaqhnLBTis3pGssASgo3ArLIYleAU
++g==
+-----END CERTIFICATE-----
diff --git a/api/current.txt b/api/current.txt
index 81ecceb..99ae1c8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2816,7 +2816,7 @@
     method public int describeContents();
     method public int getDisplayId();
     method public int getGestureId();
-    method public void writeToParcel(android.os.Parcel, int);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.accessibilityservice.AccessibilityGestureInfo> CREATOR;
   }
 
@@ -10875,9 +10875,7 @@
     method @Nullable public String getString(String, @Nullable String);
     method @Nullable public java.util.Set<java.lang.String> getStringSet(String, @Nullable java.util.Set<java.lang.String>);
     method public void registerOnSharedPreferenceChangeListener(android.content.SharedPreferences.OnSharedPreferenceChangeListener);
-    method public default void registerOnSharedPreferencesClearListener(@NonNull android.content.SharedPreferences.OnSharedPreferencesClearListener);
     method public void unregisterOnSharedPreferenceChangeListener(android.content.SharedPreferences.OnSharedPreferenceChangeListener);
-    method public default void unregisterOnSharedPreferencesClearListener(@NonNull android.content.SharedPreferences.OnSharedPreferencesClearListener);
   }
 
   public static interface SharedPreferences.Editor {
@@ -10897,10 +10895,6 @@
     method public void onSharedPreferenceChanged(android.content.SharedPreferences, String);
   }
 
-  public static interface SharedPreferences.OnSharedPreferencesClearListener {
-    method public void onSharedPreferencesClear(@NonNull android.content.SharedPreferences, @NonNull java.util.Set<java.lang.String>);
-  }
-
   public class SyncAdapterType implements android.os.Parcelable {
     ctor public SyncAdapterType(String, String, boolean, boolean);
     ctor public SyncAdapterType(android.os.Parcel);
@@ -28204,7 +28198,7 @@
     method public android.media.tv.TvTrackInfo.Builder setAudioChannelCount(int);
     method public android.media.tv.TvTrackInfo.Builder setAudioSampleRate(int);
     method public android.media.tv.TvTrackInfo.Builder setDescription(CharSequence);
-    method public android.media.tv.TvTrackInfo.Builder setEncrypted(boolean);
+    method @NonNull public android.media.tv.TvTrackInfo.Builder setEncrypted(boolean);
     method public android.media.tv.TvTrackInfo.Builder setExtra(android.os.Bundle);
     method public android.media.tv.TvTrackInfo.Builder setLanguage(String);
     method public android.media.tv.TvTrackInfo.Builder setVideoActiveFormatDescription(byte);
@@ -44082,7 +44076,7 @@
 
   public class CarrierConfigManager {
     method @Nullable public android.os.PersistableBundle getConfig();
-    method @Nullable public android.os.PersistableBundle getConfigByComponentForSubId(String, int);
+    method @Nullable public android.os.PersistableBundle getConfigByComponentForSubId(@NonNull String, int);
     method @Nullable public android.os.PersistableBundle getConfigForSubId(int);
     method public static boolean isConfigForIdentifiedCarrier(android.os.PersistableBundle);
     method public void notifyConfigChangedForSubId(int);
@@ -53727,6 +53721,7 @@
 
   public final class TextClassificationSessionId implements android.os.Parcelable {
     method public int describeContents();
+    method @NonNull public String flattenToString();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassificationSessionId> CREATOR;
   }
@@ -53814,6 +53809,7 @@
     field public static final int TYPE_AUTO_SELECTION = 5; // 0x5
     field public static final int TYPE_COPY_ACTION = 9; // 0x9
     field public static final int TYPE_CUT_ACTION = 11; // 0xb
+    field public static final int TYPE_LINKS_GENERATED = 21; // 0x15
     field public static final int TYPE_LINK_CLICKED = 7; // 0x7
     field public static final int TYPE_MANUAL_REPLY = 19; // 0x13
     field public static final int TYPE_OTHER_ACTION = 16; // 0x10
diff --git a/api/removed.txt b/api/removed.txt
index db784a8..74a9346 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -5,10 +5,6 @@
     method @Deprecated public static int getMaxNumPictureInPictureActions();
   }
 
-  public class KeyguardManager {
-    method @Deprecated public void dismissKeyguard(@NonNull android.app.Activity, @Nullable android.app.KeyguardManager.KeyguardDismissCallback, @Nullable android.os.Handler);
-  }
-
   public class Notification implements android.os.Parcelable {
     method @Deprecated public String getChannel();
     method public static Class<? extends android.app.Notification.Style> getNotificationStyleClass(String);
diff --git a/api/system-current.txt b/api/system-current.txt
index 61ca84a..e87007f 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1150,7 +1150,8 @@
     method @Nullable public final android.os.IBinder onBind(@Nullable android.content.Intent);
     method @WorkerThread public abstract boolean onClearRoleHolders(@NonNull String, int);
     method @WorkerThread public abstract boolean onGrantDefaultRoles();
-    method public abstract boolean onIsApplicationQualifiedForRole(@NonNull String, @NonNull String);
+    method @Deprecated public abstract boolean onIsApplicationQualifiedForRole(@NonNull String, @NonNull String);
+    method public boolean onIsApplicationVisibleForRole(@NonNull String, @NonNull String);
     method public abstract boolean onIsRoleVisible(@NonNull String);
     method @WorkerThread public abstract boolean onRemoveRoleHolder(@NonNull String, @NonNull String, int);
     field public static final String SERVICE_INTERFACE = "android.app.role.RoleControllerService";
@@ -1206,7 +1207,7 @@
 
   public static final class UsageEvents.Event {
     method public int getInstanceId();
-    method public String getNotificationChannelId();
+    method @Nullable public String getNotificationChannelId();
     method @Nullable public String getTaskRootClassName();
     method @Nullable public String getTaskRootPackageName();
     method public boolean isInstantApp();
diff --git a/api/test-current.txt b/api/test-current.txt
index 7e1c67d..b2ed91b 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -82,6 +82,7 @@
   }
 
   public class ActivityOptions {
+    method public static void setExitTransitionTimeout(long);
     method public void setLaunchActivityType(int);
     method public void setLaunchTaskId(int);
     method public void setLaunchWindowingMode(int);
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index 76b905d..ed717c4 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -125,6 +125,11 @@
             return;
         }
 
+        if ("autorestore".equals(op)) {
+            doAutoRestore(userId);
+            return;
+        }
+
         if ("enabled".equals(op)) {
             doEnabled(userId);
             return;
@@ -213,6 +218,26 @@
         return true;
     }
 
+    private void doAutoRestore(int userId) {
+        String arg = nextArg();
+        if (arg == null) {
+            showUsage();
+            return;
+        }
+
+        try {
+            boolean enable = Boolean.parseBoolean(arg);
+            mBmgr.setAutoRestore(enable);
+            System.out.println(
+                    "Auto restore is now "
+                            + (enable ? "enabled" : "disabled")
+                            + " for user "
+                            + userId);
+        } catch (RemoteException e) {
+            handleRemoteException(e);
+        }
+    }
+
     private String activatedToString(boolean activated) {
         return activated ? "activated" : "deactivated";
     }
@@ -918,6 +943,7 @@
         System.err.println("       bmgr init TRANSPORT...");
         System.err.println("       bmgr activate BOOL");
         System.err.println("       bmgr activated");
+        System.err.println("       bmgr autorestore BOOL");
         System.err.println("");
         System.err.println("The '--user' option specifies the user on which the operation is run.");
         System.err.println("It must be the first argument before the operation.");
@@ -992,6 +1018,9 @@
         System.err.println("");
         System.err.println("The 'activated' command reports the current activated/deactivated");
         System.err.println("state of the backup mechanism.");
+        System.err.println("");
+        System.err.println("The 'autorestore' command enables or disables automatic restore when");
+        System.err.println("a new package is installed.");
     }
 
     private static class BackupMonitor extends IBackupManagerMonitor.Stub {
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index b01b0a8..2732779 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -337,7 +337,7 @@
     }
 
     // Pulled events will start at field 10000.
-    // Next: 10062
+    // Next: 10064
     oneof pulled {
         WifiBytesTransfer wifi_bytes_transfer = 10000;
         WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001;
@@ -401,6 +401,8 @@
         CoolingDevice cooling_device = 10059;
         AppOps app_ops = 10060;
         ProcessSystemIonHeapSize process_system_ion_heap_size = 10061;
+        SurfaceflingerStatsGlobalInfo surfaceflinger_stats_global_info = 10062;
+        SurfaceflingerStatsLayerInfo surfaceflinger_stats_layer_info = 10063;
     }
 
     // DO NOT USE field numbers above 100,000 in AOSP.
@@ -7087,3 +7089,77 @@
     // The number of reboot of the device during a successful update.
     optional int32 reboot_count = 7;
 }
+
+/**
+ * Global display pipeline metrics reported by SurfaceFlinger.
+ * Pulled from:
+ *    frameworks/native/services/surfaceflinger/TimeStats/TimeStats.cpp
+ */
+message SurfaceflingerStatsGlobalInfo {
+    // Total number of frames presented during the tracing period
+    optional int64 total_frames = 1;
+    // Total number of frames missed
+    optional int64 missed_frames = 2;
+    // Total number of frames that fell back to client composition
+    optional int64 client_composition_frames = 3;
+    // Total time the display was turned on
+    optional int64 display_on_millis = 4;
+    // Total time that was spent performing animations.
+    // This is derived from the present-to-present layer histogram
+    optional int64 animation_millis = 5;
+}
+
+/**
+ * Per-layer display pipeline metrics reported by SurfaceFlinger.
+ * The number of layers uploaded will be restricted due to size limitations.
+ * Pulled from:
+ *    frameworks/native/services/surfaceflinger/TimeStats/TimeStats.cpp
+ */
+message SurfaceflingerStatsLayerInfo {
+    // The layer for this set of metrics
+    // For now we can infer that the package name is included in the layer
+    // name.
+    optional string layer_name = 1;
+    // Total number of frames presented
+    optional int64 total_frames = 2;
+    // Total number of dropped frames while latching a buffer for this layer.
+    optional int64 dropped_frames = 3;
+    // Set of timings measured between successive presentation timestamps.
+    optional FrameTimingHistogram present_to_present = 4
+        [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Set of timings measured from when an app queued a buffer for
+    // presentation, until the buffer was actually presented to the
+    // display.
+    optional FrameTimingHistogram post_to_present = 5
+        [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Set of timings measured from when a buffer is ready to be presented,
+    // until the buffer was actually presented to the display.
+    optional FrameTimingHistogram acquire_to_present = 6
+        [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Set of timings measured from when a buffer was latched by
+    // SurfaceFlinger, until the buffer was presented to the display
+    optional FrameTimingHistogram latch_to_present = 7
+        [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Set of timings measured from the desired presentation to the actual
+    // presentation time
+    optional FrameTimingHistogram desired_to_present = 8
+        [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Set of timings measured from when an app queued a buffer for
+    // presentation, until the buffer was ready to be presented.
+    optional FrameTimingHistogram post_to_acquire = 9
+        [(android.os.statsd.log_mode) = MODE_BYTES];
+}
+
+/**
+ * Histogram of frame counts bucketed by time in milliseconds.
+ * Because of size limitations, we hard-cap the number of buckets, with
+ * buckets for corresponding to larger milliseconds being less precise.
+ */
+message FrameTimingHistogram {
+    // Timings in milliseconds that describes a set of histogram buckets
+    repeated int32 time_millis_buckets = 1;
+    // Number of frames that match to each time_millis, i.e. the bucket
+    // contents
+    // It's required that len(time_millis) == len(frame_count)
+    repeated int64 frame_counts = 2;
+}
diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp
index 68082c2..42132ee 100644
--- a/cmds/statsd/src/main.cpp
+++ b/cmds/statsd/src/main.cpp
@@ -78,7 +78,7 @@
     ps->giveThreadPoolName();
     IPCThreadState::self()->disableBackgroundScheduling(true);
 
-    ::android::hardware::configureRpcThreadpool(1 /*threads*/, false /*willJoin*/);
+    ::android::hardware::configureRpcThreadpool(4 /*threads*/, false /*willJoin*/);
 
     std::shared_ptr<LogEventQueue> eventQueue =
             std::make_shared<LogEventQueue>(2000 /*buffer limit. Buffer is NOT pre-allocated*/);
diff --git a/config/hiddenapi-greylist-max-o.txt b/config/hiddenapi-greylist-max-o.txt
index d9c1cd0..15026b0 100644
--- a/config/hiddenapi-greylist-max-o.txt
+++ b/config/hiddenapi-greylist-max-o.txt
@@ -3040,7 +3040,6 @@
 Landroid/app/admin/IDevicePolicyManager$Stub$Proxy;->retrieveSecurityLogs(Landroid/content/ComponentName;)Landroid/content/pm/ParceledListSlice;
 Landroid/app/admin/IDevicePolicyManager$Stub$Proxy;->setAccountManagementDisabled(Landroid/content/ComponentName;Ljava/lang/String;Z)V
 Landroid/app/admin/IDevicePolicyManager$Stub$Proxy;->setActiveAdmin(Landroid/content/ComponentName;ZI)V
-Landroid/app/admin/IDevicePolicyManager$Stub$Proxy;->setActivePasswordState(Landroid/app/admin/PasswordMetrics;I)V
 Landroid/app/admin/IDevicePolicyManager$Stub$Proxy;->setAffiliationIds(Landroid/content/ComponentName;Ljava/util/List;)V
 Landroid/app/admin/IDevicePolicyManager$Stub$Proxy;->setAlwaysOnVpnPackage(Landroid/content/ComponentName;Ljava/lang/String;Z)Z
 Landroid/app/admin/IDevicePolicyManager$Stub$Proxy;->setApplicationHidden(Landroid/content/ComponentName;Ljava/lang/String;Ljava/lang/String;Z)Z
@@ -3305,7 +3304,6 @@
 Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_retrieveSecurityLogs:I
 Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_setAccountManagementDisabled:I
 Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_setActiveAdmin:I
-Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_setActivePasswordState:I
 Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_setAffiliationIds:I
 Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_setAlwaysOnVpnPackage:I
 Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_setApplicationHidden:I
@@ -3569,7 +3567,6 @@
 Landroid/app/admin/IDevicePolicyManager;->retrieveSecurityLogs(Landroid/content/ComponentName;)Landroid/content/pm/ParceledListSlice;
 Landroid/app/admin/IDevicePolicyManager;->setAccountManagementDisabled(Landroid/content/ComponentName;Ljava/lang/String;Z)V
 Landroid/app/admin/IDevicePolicyManager;->setActiveAdmin(Landroid/content/ComponentName;ZI)V
-Landroid/app/admin/IDevicePolicyManager;->setActivePasswordState(Landroid/app/admin/PasswordMetrics;I)V
 Landroid/app/admin/IDevicePolicyManager;->setAffiliationIds(Landroid/content/ComponentName;Ljava/util/List;)V
 Landroid/app/admin/IDevicePolicyManager;->setAlwaysOnVpnPackage(Landroid/content/ComponentName;Ljava/lang/String;Z)Z
 Landroid/app/admin/IDevicePolicyManager;->setApplicationHidden(Landroid/content/ComponentName;Ljava/lang/String;Ljava/lang/String;Z)Z
diff --git a/core/java/android/accessibilityservice/AccessibilityGestureInfo.java b/core/java/android/accessibilityservice/AccessibilityGestureInfo.java
index dc50a4c..28c1dea 100644
--- a/core/java/android/accessibilityservice/AccessibilityGestureInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityGestureInfo.java
@@ -114,6 +114,7 @@
         return mGestureId;
     }
 
+    @NonNull
     @Override
     public String toString() {
         StringBuilder stringBuilder = new StringBuilder("AccessibilityGestureInfo[");
@@ -133,7 +134,7 @@
     }
 
     @Override
-    public void writeToParcel(Parcel parcel, int flags) {
+    public void writeToParcel(@NonNull Parcel parcel, int flags) {
         parcel.writeInt(mGestureId);
         parcel.writeInt(mDisplayId);
     }
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 4730bd0..a8daf91 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -635,7 +635,7 @@
      * Gets the root node in the currently active window if this service
      * can retrieve window content. The active window is the one that the user
      * is currently touching or the window with input focus, if the user is not
-     * touching any window.
+     * touching any window. It could be from any logical display.
      * <p>
      * The currently active window is defined as the window that most recently fired one
      * of the following events:
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index b8d9575..6772884 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -829,6 +829,17 @@
         return exit;
     }
 
+    /**
+     * Needed for virtual devices because they can be slow enough that the 1 second timeout
+     * triggers when it doesn't on normal devices.
+     *
+     * @hide
+     */
+    @TestApi
+    public static void setExitTransitionTimeout(long timeoutMillis) {
+        ExitTransitionCoordinator.sMaxWaitMillis = timeoutMillis;
+    }
+
     /** @hide */
     static ActivityOptions makeSceneTransitionAnimation(Activity activity,
             ExitTransitionCoordinator exitCoordinator, ArrayList<String> sharedElementNames,
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 34045c9..9353e0b 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -30,7 +30,6 @@
 import android.app.usage.UsageStatsManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ParceledListSlice;
 import android.media.AudioAttributes.AttributeUsage;
 import android.os.Binder;
@@ -3220,7 +3219,7 @@
         }
 
         @Override
-        public boolean equals(Object obj) {
+        public boolean equals(@Nullable Object obj) {
             if (this == obj) {
                 return true;
             }
@@ -3251,6 +3250,7 @@
             return result;
         }
 
+        @NonNull
         @Override
         public String toString() {
             return getClass().getSimpleName() + "[from:"
@@ -3486,7 +3486,7 @@
         };
 
         @Override
-        public boolean equals(Object obj) {
+        public boolean equals(@Nullable Object obj) {
             if (this == obj) {
                 return true;
             }
@@ -3718,7 +3718,7 @@
         };
 
         @Override
-        public boolean equals(Object obj) {
+        public boolean equals(@Nullable Object obj) {
             if (this == obj) {
                 return true;
             }
@@ -4072,7 +4072,7 @@
         }
 
         @Override
-        public boolean equals(Object obj) {
+        public boolean equals(@Nullable Object obj) {
             if (this == obj) {
                 return true;
             }
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 0478ac8..d74399c 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -127,6 +127,7 @@
      * @hide
      */
     public static final boolean DEBUG_TRACE_GRANTS = false;
+    public static final boolean DEBUG_TRACE_PERMISSION_UPDATES = false;
 
     private static final int DEFAULT_EPHEMERAL_COOKIE_MAX_SIZE_BYTES = 16384; // 16KB
 
@@ -690,7 +691,7 @@
             UserHandle user) {
         if (DEBUG_TRACE_GRANTS
                 && shouldTraceGrant(packageName, permissionName, user.getIdentifier())) {
-            Log.i(TAG, "App " + mContext.getPackageName() + " is granting "
+            Log.i(TAG, "App " + mContext.getPackageName() + " is granting " + packageName + " "
                     + permissionName + " for user " + user.getIdentifier(), new RuntimeException());
         }
         try {
@@ -708,9 +709,9 @@
 
     @Override
     public void revokeRuntimePermission(String packageName, String permName, UserHandle user) {
-        if (DEBUG_TRACE_GRANTS
+        if (DEBUG_TRACE_PERMISSION_UPDATES
                 && shouldTraceGrant(packageName, permName, user.getIdentifier())) {
-            Log.i(TAG, "App " + mContext.getPackageName() + " is revoking "
+            Log.i(TAG, "App " + mContext.getPackageName() + " is revoking " + packageName + " "
                     + permName + " for user " + user.getIdentifier(), new RuntimeException());
         }
         try {
@@ -734,9 +735,10 @@
     @Override
     public void updatePermissionFlags(String permName, String packageName,
             int flagMask, int flagValues, UserHandle user) {
-        if (DEBUG_TRACE_GRANTS
+        if (DEBUG_TRACE_PERMISSION_UPDATES
                 && shouldTraceGrant(packageName, permName, user.getIdentifier())) {
             Log.i(TAG, "App " + mContext.getPackageName() + " is updating flags for "
+                    + packageName + " "
                     + permName + " for user " + user.getIdentifier() + ": "
                     + DebugUtils.flagsToString(PackageManager.class, "FLAG_PERMISSION_", flagMask)
                     + " := " + DebugUtils.flagsToString(
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index 48a711e..68824cd 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -48,7 +48,7 @@
  */
 class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
     private static final String TAG = "ExitTransitionCoordinator";
-    private static final long MAX_WAIT_MS = 1000;
+    static long sMaxWaitMillis = 1000;
 
     private Bundle mSharedElementBundle;
     private boolean mExitNotified;
@@ -120,7 +120,7 @@
 
     private void delayCancel() {
         if (mHandler != null) {
-            mHandler.sendEmptyMessageDelayed(MSG_CANCEL, MAX_WAIT_MS);
+            mHandler.sendEmptyMessageDelayed(MSG_CANCEL, sMaxWaitMillis);
         }
     }
 
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 6677587..9b667a11 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -32,7 +32,6 @@
 import android.hardware.biometrics.BiometricPrompt;
 import android.os.Binder;
 import android.os.Build;
-import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -508,13 +507,6 @@
         }
     }
 
-    /** @removed */
-    @Deprecated
-    public void dismissKeyguard(@NonNull Activity activity,
-            @Nullable KeyguardDismissCallback callback, @Nullable Handler handler) {
-        requestDismissKeyguard(activity, callback);
-    }
-
     /**
      * If the device is currently locked (see {@link #isKeyguardLocked()}, requests the Keyguard to
      * be dismissed.
diff --git a/core/java/android/app/SharedPreferencesImpl.java b/core/java/android/app/SharedPreferencesImpl.java
index 9162626..9f865b4 100644
--- a/core/java/android/app/SharedPreferencesImpl.java
+++ b/core/java/android/app/SharedPreferencesImpl.java
@@ -16,17 +16,19 @@
 
 package android.app;
 
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
+import android.compat.Compatibility;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
 import android.content.SharedPreferences;
+import android.os.Build;
 import android.os.FileUtils;
 import android.os.Looper;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.StructStat;
 import android.system.StructTimespec;
-import android.util.ArraySet;
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
@@ -62,6 +64,15 @@
     /** If a fsync takes more than {@value #MAX_FSYNC_DURATION_MILLIS} ms, warn */
     private static final long MAX_FSYNC_DURATION_MILLIS = 256;
 
+    /**
+     * There will now be a callback to {@link
+     * OnSharedPreferenceChangeListener#onSharedPreferenceChanged(SharedPreferences, String)} with
+     * a {@code null} key on {@link Editor#clear()}.
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
+    private static final long CALLBACK_ON_CLEAR_CHANGE = 119147584L;
+
     // Lock ordering rules:
     //  - acquire SharedPreferencesImpl.mLock before EditorImpl.mLock
     //  - acquire mWritingToDiskLock before EditorImpl.mLock
@@ -94,10 +105,6 @@
     private final WeakHashMap<OnSharedPreferenceChangeListener, Object> mListeners =
             new WeakHashMap<OnSharedPreferenceChangeListener, Object>();
 
-    @GuardedBy("mLock")
-    private final WeakHashMap<OnSharedPreferencesClearListener, Object> mClearListeners =
-            new WeakHashMap<>();
-
     /** Current memory state (always increasing) */
     @GuardedBy("this")
     private long mCurrentMemoryStateGeneration;
@@ -258,28 +265,6 @@
         }
     }
 
-    @Override
-    public void registerOnSharedPreferencesClearListener(
-            @NonNull OnSharedPreferencesClearListener listener) {
-        if (listener == null) {
-            throw new IllegalArgumentException("listener cannot be null.");
-        }
-        synchronized (mLock) {
-            mClearListeners.put(listener, CONTENT);
-        }
-    }
-
-    @Override
-    public void unregisterOnSharedPreferencesClearListener(
-            @NonNull OnSharedPreferencesClearListener listener) {
-        if (listener == null) {
-            throw new IllegalArgumentException("listener cannot be null.");
-        }
-        synchronized (mLock) {
-            mClearListeners.remove(listener);
-        }
-    }
-
     @GuardedBy("mLock")
     private void awaitLoadedLocked() {
         if (!mLoaded) {
@@ -388,10 +373,9 @@
     // Return value from EditorImpl#commitToMemory()
     private static class MemoryCommitResult {
         final long memoryStateGeneration;
+        final boolean keysCleared;
         @Nullable final List<String> keysModified;
-        @Nullable final Set<String> keysCleared;
         @Nullable final Set<OnSharedPreferenceChangeListener> listeners;
-        @Nullable final Set<OnSharedPreferencesClearListener> clearListeners;
         final Map<String, Object> mapToWriteToDisk;
         final CountDownLatch writtenToDiskLatch = new CountDownLatch(1);
 
@@ -399,16 +383,14 @@
         volatile boolean writeToDiskResult = false;
         boolean wasWritten = false;
 
-        private MemoryCommitResult(long memoryStateGeneration, @Nullable List<String> keysModified,
+        private MemoryCommitResult(long memoryStateGeneration, boolean keysCleared,
+                @Nullable List<String> keysModified,
                 @Nullable Set<OnSharedPreferenceChangeListener> listeners,
-                @Nullable Set<String> keysCleared,
-                @Nullable Set<OnSharedPreferencesClearListener> clearListeners,
                 Map<String, Object> mapToWriteToDisk) {
             this.memoryStateGeneration = memoryStateGeneration;
+            this.keysCleared = keysCleared;
             this.keysModified = keysModified;
             this.listeners = listeners;
-            this.keysCleared = keysCleared;
-            this.clearListeners = clearListeners;
             this.mapToWriteToDisk = mapToWriteToDisk;
         }
 
@@ -526,16 +508,14 @@
             // SharedPreferences instance back, which has the
             // changes reflected in memory.
             notifyListeners(mcr);
-            notifyClearListeners(mcr);
         }
 
         // Returns true if any changes were made
         private MemoryCommitResult commitToMemory() {
             long memoryStateGeneration;
+            boolean keysCleared = false;
             List<String> keysModified = null;
-            Set<String> keysCleared = null;
             Set<OnSharedPreferenceChangeListener> listeners = null;
-            Set<OnSharedPreferencesClearListener> clearListeners = null;
             Map<String, Object> mapToWriteToDisk;
 
             synchronized (SharedPreferencesImpl.this.mLock) {
@@ -557,23 +537,16 @@
                     keysModified = new ArrayList<String>();
                     listeners = new HashSet<OnSharedPreferenceChangeListener>(mListeners.keySet());
                 }
-                boolean hasClearListeners = !mClearListeners.isEmpty();
-                if (hasClearListeners) {
-                    keysCleared = new ArraySet<>();
-                    clearListeners = new HashSet<>(mClearListeners.keySet());
-                }
 
                 synchronized (mEditorLock) {
                     boolean changesMade = false;
 
                     if (mClear) {
                         if (!mapToWriteToDisk.isEmpty()) {
-                            if (hasClearListeners) {
-                                keysCleared.addAll(mapToWriteToDisk.keySet());
-                            }
                             changesMade = true;
                             mapToWriteToDisk.clear();
                         }
+                        keysCleared = true;
                         mClear = false;
                     }
 
@@ -613,8 +586,8 @@
                     memoryStateGeneration = mCurrentMemoryStateGeneration;
                 }
             }
-            return new MemoryCommitResult(memoryStateGeneration, keysModified, listeners,
-                    keysCleared, clearListeners, mapToWriteToDisk);
+            return new MemoryCommitResult(memoryStateGeneration, keysCleared, keysModified,
+                    listeners, mapToWriteToDisk);
         }
 
         @Override
@@ -641,16 +614,21 @@
                 }
             }
             notifyListeners(mcr);
-            notifyClearListeners(mcr);
             return mcr.writeToDiskResult;
         }
 
         private void notifyListeners(final MemoryCommitResult mcr) {
-            if (mcr.listeners == null || mcr.keysModified == null ||
-                mcr.keysModified.size() == 0) {
+            if (mcr.listeners == null || (mcr.keysModified == null && !mcr.keysCleared)) {
                 return;
             }
             if (Looper.myLooper() == Looper.getMainLooper()) {
+                if (mcr.keysCleared && Compatibility.isChangeEnabled(CALLBACK_ON_CLEAR_CHANGE)) {
+                    for (OnSharedPreferenceChangeListener listener : mcr.listeners) {
+                        if (listener != null) {
+                            listener.onSharedPreferenceChanged(SharedPreferencesImpl.this, null);
+                        }
+                    }
+                }
                 for (int i = mcr.keysModified.size() - 1; i >= 0; i--) {
                     final String key = mcr.keysModified.get(i);
                     for (OnSharedPreferenceChangeListener listener : mcr.listeners) {
@@ -664,24 +642,6 @@
                 ActivityThread.sMainThreadHandler.post(() -> notifyListeners(mcr));
             }
         }
-
-        private void notifyClearListeners(final MemoryCommitResult mcr) {
-            if (mcr.clearListeners == null || mcr.keysCleared == null
-                    || mcr.keysCleared.isEmpty()) {
-                return;
-            }
-            if (Looper.myLooper() == Looper.getMainLooper()) {
-                for (OnSharedPreferencesClearListener listener : mcr.clearListeners) {
-                    if (listener != null) {
-                        listener.onSharedPreferencesClear(SharedPreferencesImpl.this,
-                                mcr.keysCleared);
-                    }
-                }
-            } else {
-                // Run this function on the main thread.
-                ActivityThread.sMainThreadHandler.post(() -> notifyClearListeners(mcr));
-            }
-        }
     }
 
     /**
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 205e7a1..28413be 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -620,6 +620,7 @@
             mNotificationIcons = true;
         }
 
+        @NonNull
         @Override
         public String toString() {
             StringBuilder sb = new StringBuilder();
diff --git a/core/java/android/app/Vr2dDisplayProperties.java b/core/java/android/app/Vr2dDisplayProperties.java
index fc200bf..d2a49fb 100644
--- a/core/java/android/app/Vr2dDisplayProperties.java
+++ b/core/java/android/app/Vr2dDisplayProperties.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -74,6 +75,7 @@
         return result;
     }
 
+    @NonNull
     @Override
     public String toString() {
         return "Vr2dDisplayProperties{"
@@ -86,7 +88,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
 
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index ff5a043..a136bbd 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -5764,21 +5764,6 @@
     /**
      * @hide
      */
-    @UnsupportedAppUsage
-    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
-    public void setActivePasswordState(PasswordMetrics metrics, int userHandle) {
-        if (mService != null) {
-            try {
-                mService.setActivePasswordState(metrics, userHandle);
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
-        }
-    }
-
-    /**
-     * @hide
-     */
     @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public void reportPasswordChanged(@UserIdInt int userId) {
         if (mService != null) {
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 5cdef6d..0da5b7a 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -131,7 +131,6 @@
     void forceRemoveActiveAdmin(in ComponentName policyReceiver, int userHandle);
     boolean hasGrantedPolicy(in ComponentName policyReceiver, int usesPolicy, int userHandle);
 
-    void setActivePasswordState(in PasswordMetrics metrics, int userHandle);
     void reportPasswordChanged(int userId);
     void reportFailedPasswordAttempt(int userHandle);
     void reportSuccessfulPasswordAttempt(int userHandle);
diff --git a/core/java/android/app/backup/RestoreDescription.java b/core/java/android/app/backup/RestoreDescription.java
index 7854394..498b686 100644
--- a/core/java/android/app/backup/RestoreDescription.java
+++ b/core/java/android/app/backup/RestoreDescription.java
@@ -16,6 +16,7 @@
 
 package android.app.backup;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -52,6 +53,7 @@
     /** This package's restore data is a tarball-type full data stream */
     public static final int TYPE_FULL_STREAM = 2;
 
+    @NonNull
     @Override
     public String toString() {
         return "RestoreDescription{" + mPackageName + " : "
diff --git a/core/java/android/app/prediction/AppPredictionContext.java b/core/java/android/app/prediction/AppPredictionContext.java
index 298b003..d14238b 100644
--- a/core/java/android/app/prediction/AppPredictionContext.java
+++ b/core/java/android/app/prediction/AppPredictionContext.java
@@ -90,7 +90,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (o == this) return true;
         if (!getClass().equals(o != null ? o.getClass() : null)) return false;
 
diff --git a/core/java/android/app/prediction/AppPredictionSessionId.java b/core/java/android/app/prediction/AppPredictionSessionId.java
index 281a16f..e5e06f8 100644
--- a/core/java/android/app/prediction/AppPredictionSessionId.java
+++ b/core/java/android/app/prediction/AppPredictionSessionId.java
@@ -16,6 +16,7 @@
 package android.app.prediction;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.os.Parcel;
@@ -46,7 +47,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (!getClass().equals(o != null ? o.getClass() : null)) return false;
 
         AppPredictionSessionId other = (AppPredictionSessionId) o;
diff --git a/core/java/android/app/prediction/AppTarget.java b/core/java/android/app/prediction/AppTarget.java
index 147c500..6f21490 100644
--- a/core/java/android/app/prediction/AppTarget.java
+++ b/core/java/android/app/prediction/AppTarget.java
@@ -151,7 +151,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (!getClass().equals(o != null ? o.getClass() : null)) return false;
 
         AppTarget other = (AppTarget) o;
diff --git a/core/java/android/app/prediction/AppTargetEvent.java b/core/java/android/app/prediction/AppTargetEvent.java
index 54b9563..26ff0c1 100644
--- a/core/java/android/app/prediction/AppTargetEvent.java
+++ b/core/java/android/app/prediction/AppTargetEvent.java
@@ -98,7 +98,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (!getClass().equals(o != null ? o.getClass() : null)) return false;
 
         AppTargetEvent other = (AppTargetEvent) o;
diff --git a/core/java/android/app/prediction/AppTargetId.java b/core/java/android/app/prediction/AppTargetId.java
index 3603f5f..052fdc1 100644
--- a/core/java/android/app/prediction/AppTargetId.java
+++ b/core/java/android/app/prediction/AppTargetId.java
@@ -16,6 +16,7 @@
 package android.app.prediction;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.os.Parcel;
@@ -59,7 +60,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (!getClass().equals(o != null ? o.getClass() : null)) return false;
 
         AppTargetId other = (AppTargetId) o;
diff --git a/core/java/android/app/role/IRoleController.aidl b/core/java/android/app/role/IRoleController.aidl
index 19762e0..8a43d7f 100644
--- a/core/java/android/app/role/IRoleController.aidl
+++ b/core/java/android/app/role/IRoleController.aidl
@@ -36,5 +36,8 @@
     void isApplicationQualifiedForRole(in String roleName, in String packageName,
             in RemoteCallback callback);
 
+    void isApplicationVisibleForRole(in String roleName, in String packageName,
+            in RemoteCallback callback);
+
     void isRoleVisible(in String roleName, in RemoteCallback callback);
 }
diff --git a/core/java/android/app/role/RoleControllerManager.java b/core/java/android/app/role/RoleControllerManager.java
index 98b11a7..16ddbc1 100644
--- a/core/java/android/app/role/RoleControllerManager.java
+++ b/core/java/android/app/role/RoleControllerManager.java
@@ -183,6 +183,9 @@
 
     /**
      * @see RoleControllerService#onIsApplicationQualifiedForRole(String, String)
+     *
+     * @deprecated Use {@link #isApplicationVisibleForRole(String, String, Executor, Consumer)}
+     *             instead.
      */
     @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
     public void isApplicationQualifiedForRole(@NonNull String roleName, @NonNull String packageName,
@@ -197,6 +200,21 @@
     }
 
     /**
+     * @see RoleControllerService#onIsApplicationVisibleForRole(String, String)
+     */
+    @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
+    public void isApplicationVisibleForRole(@NonNull String roleName, @NonNull String packageName,
+            @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
+        AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> {
+            AndroidFuture<Bundle> future = new AndroidFuture<>();
+            service.isApplicationVisibleForRole(roleName, packageName,
+                    new RemoteCallback(future::complete));
+            return future;
+        });
+        propagateCallback(operation, "isApplicationVisibleForRole", executor, callback);
+    }
+
+    /**
      * @see RoleControllerService#onIsRoleVisible(String)
      */
     @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
diff --git a/core/java/android/app/role/RoleControllerService.java b/core/java/android/app/role/RoleControllerService.java
index 2bc9456..85db6a4 100644
--- a/core/java/android/app/role/RoleControllerService.java
+++ b/core/java/android/app/role/RoleControllerService.java
@@ -153,6 +153,20 @@
             }
 
             @Override
+            public void isApplicationVisibleForRole(String roleName, String packageName,
+                    RemoteCallback callback) {
+                enforceCallingPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, null);
+
+                Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+                Preconditions.checkStringNotEmpty(packageName,
+                        "packageName cannot be null or empty");
+                Preconditions.checkNotNull(callback, "callback cannot be null");
+
+                boolean visible = onIsApplicationVisibleForRole(roleName, packageName);
+                callback.sendResult(visible ? Bundle.EMPTY : null);
+            }
+
+            @Override
             public void isRoleVisible(String roleName, RemoteCallback callback) {
                 enforceCallingPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, null);
 
@@ -256,11 +270,26 @@
      * @param packageName package name of the application to check for
      *
      * @return whether the application is qualified for the role
+     *
+     * @deprecated Implement {@link #onIsApplicationVisibleForRole(String, String)} instead.
      */
     public abstract boolean onIsApplicationQualifiedForRole(@NonNull String roleName,
             @NonNull String packageName);
 
     /**
+     * Check whether an application is visible for a role.
+     *
+     * @param roleName name of the role to check for
+     * @param packageName package name of the application to check for
+     *
+     * @return whether the application is visible for the role
+     */
+    public boolean onIsApplicationVisibleForRole(@NonNull String roleName,
+            @NonNull String packageName) {
+        return onIsApplicationQualifiedForRole(roleName, packageName);
+    }
+
+    /**
      * Check whether a role should be visible to user.
      *
      * @param roleName name of the role to check for
diff --git a/core/java/android/app/usage/CacheQuotaHint.java b/core/java/android/app/usage/CacheQuotaHint.java
index b92d538..b5aed49f 100644
--- a/core/java/android/app/usage/CacheQuotaHint.java
+++ b/core/java/android/app/usage/CacheQuotaHint.java
@@ -81,7 +81,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (o instanceof CacheQuotaHint) {
             final CacheQuotaHint other = (CacheQuotaHint) o;
             return Objects.equals(mUuid, other.mUuid)
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index b564c31..84c6855 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -554,6 +554,7 @@
          * event is of type {@link #NOTIFICATION_INTERRUPTION}, otherwise it returns null;
          * @hide
          */
+        @Nullable
         @SystemApi
         public String getNotificationChannelId() {
             return mNotificationChannelId;
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
index fb78789..cfb363a08 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -118,6 +118,8 @@
      */
     public static final int PAN_OPERATION_SUCCESS = 1004;
 
+    private final Context mContext;
+
     private BluetoothAdapter mAdapter;
     private final BluetoothProfileConnector<IBluetoothPan> mProfileConnector =
             new BluetoothProfileConnector(this, BluetoothProfile.PAN,
@@ -136,6 +138,7 @@
     @UnsupportedAppUsage
     /*package*/ BluetoothPan(Context context, ServiceListener listener) {
         mAdapter = BluetoothAdapter.getDefaultAdapter();
+        mContext = context;
         mProfileConnector.connect(context, listener);
     }
 
@@ -287,11 +290,12 @@
 
     @UnsupportedAppUsage
     public void setBluetoothTethering(boolean value) {
-        if (DBG) log("setBluetoothTethering(" + value + ")");
+        String pkgName = mContext.getOpPackageName();
+        if (DBG) log("setBluetoothTethering(" + value + "), calling package:" + pkgName);
         final IBluetoothPan service = getService();
         if (service != null && isEnabled()) {
             try {
-                service.setBluetoothTethering(value);
+                service.setBluetoothTethering(value, pkgName);
             } catch (RemoteException e) {
                 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
             }
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index f297c06..9dbfbc7 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -1033,12 +1033,13 @@
 
     /** @hide */
     public final void setTransportLoggingEnabled(boolean enabled) {
-        if (mTransport != null) {
-            if (enabled) {
-                mTransport.mInterface = new LoggingContentInterface(getClass().getSimpleName(), this);
-            } else {
-                mTransport.mInterface = this;
-            }
+        if (mTransport == null) {
+            return;
+        }
+        if (enabled) {
+            mTransport.mInterface = new LoggingContentInterface(getClass().getSimpleName(), this);
+        } else {
+            mTransport.mInterface = this;
         }
     }
 
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
index 621f331..5c2de57 100644
--- a/core/java/android/content/ContentProviderOperation.java
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -684,10 +684,26 @@
             return new ContentProviderOperation(this);
         }
 
-        private void setValue(@NonNull String key, @NonNull Object value) {
+        private void ensureValues() {
             if (mValues == null) {
                 mValues = new ArrayMap<>();
             }
+        }
+
+        private void ensureExtras() {
+            if (mExtras == null) {
+                mExtras = new ArrayMap<>();
+            }
+        }
+
+        private void ensureSelectionArgs() {
+            if (mSelectionArgs == null) {
+                mSelectionArgs = new SparseArray<>();
+            }
+        }
+
+        private void setValue(@NonNull String key, @NonNull Object value) {
+            ensureValues();
             final boolean oldReference = mValues.get(key) instanceof BackReference;
             final boolean newReference = value instanceof BackReference;
             if (!oldReference || newReference) {
@@ -696,9 +712,7 @@
         }
 
         private void setExtra(@NonNull String key, @NonNull Object value) {
-            if (mExtras == null) {
-                mExtras = new ArrayMap<>();
-            }
+            ensureExtras();
             final boolean oldReference = mExtras.get(key) instanceof BackReference;
             final boolean newReference = value instanceof BackReference;
             if (!oldReference || newReference) {
@@ -707,9 +721,7 @@
         }
 
         private void setSelectionArg(int index, @NonNull Object value) {
-            if (mSelectionArgs == null) {
-                mSelectionArgs = new SparseArray<>();
-            }
+            ensureSelectionArgs();
             final boolean oldReference = mSelectionArgs.get(index) instanceof BackReference;
             final boolean newReference = value instanceof BackReference;
             if (!oldReference || newReference) {
@@ -728,6 +740,7 @@
          */
         public @NonNull Builder withValues(@NonNull ContentValues values) {
             assertValuesAllowed();
+            ensureValues();
             final ArrayMap<String, Object> rawValues = values.getValues();
             for (int i = 0; i < rawValues.size(); i++) {
                 setValue(rawValues.keyAt(i), rawValues.valueAt(i));
@@ -815,6 +828,7 @@
          */
         public @NonNull Builder withExtras(@NonNull Bundle extras) {
             assertExtrasAllowed();
+            ensureExtras();
             for (String key : extras.keySet()) {
                 setExtra(key, extras.get(key));
             }
@@ -885,6 +899,7 @@
             assertSelectionAllowed();
             mSelection = selection;
             if (selectionArgs != null) {
+                ensureSelectionArgs();
                 for (int i = 0; i < selectionArgs.length; i++) {
                     setSelectionArg(i, selectionArgs[i]);
                 }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 5dcc291..b612f1c 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -854,11 +854,16 @@
      * to any callers for the same name, meaning they will see each other's
      * edits as soon as they are made.
      *
-     * This method is thead-safe.
+     * <p>This method is thread-safe.
      *
-     * @param name Desired preferences file. If a preferences file by this name
-     * does not exist, it will be created when you retrieve an
-     * editor (SharedPreferences.edit()) and then commit changes (Editor.commit()).
+     * <p>If the preferences directory does not already exist, it will be created when this method
+     * is called.
+     *
+     * <p>If a preferences file by this name does not exist, it will be created when you retrieve an
+     * editor ({@link SharedPreferences#edit()}) and then commit changes ({@link
+     * SharedPreferences.Editor#commit()} or {@link SharedPreferences.Editor#apply()}).
+     *
+     * @param name Desired preferences file.
      * @param mode Operating mode.
      *
      * @return The single {@link SharedPreferences} instance that can be used
diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java
index 9d87e25..c193868 100644
--- a/core/java/android/content/SharedPreferences.java
+++ b/core/java/android/content/SharedPreferences.java
@@ -16,7 +16,6 @@
 
 package android.content;
 
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 
 import java.util.Map;
@@ -58,33 +57,18 @@
          *
          * <p>This callback will be run on your main thread.
          *
-         * <p><em>Note: This callback will not be triggered when preferences are cleared via
-         * {@link Editor#clear()}. However, from {@link android.os.Build.VERSION_CODES#R Android R}
-         * onwards, you can use {@link OnSharedPreferencesClearListener} to register for
-         * {@link Editor#clear()} callbacks.</em>
-         *
-         * @param sharedPreferences The {@link SharedPreferences} that received
-         *            the change.
-         * @param key The key of the preference that was changed, added, or
-         *            removed.
-         */
-        void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key);
-    }
-
-    /**
-     * Interface definition for a callback to be invoked when shared preferences are cleared.
-     */
-    public interface OnSharedPreferencesClearListener {
-        /**
-         * Called when shared preferences are cleared via {@link Editor#clear()}.
-         *
-         * <p>This callback will be run on your main thread.
+         * <p><em>Note: This callback will not be triggered when preferences are cleared
+         * via {@link Editor#clear()}, unless targeting {@link android.os.Build.VERSION_CODES#R}
+         * on devices running OS versions {@link android.os.Build.VERSION_CODES#R Android R}
+         * or later.</em>
          *
          * @param sharedPreferences The {@link SharedPreferences} that received the change.
-         * @param keys The set of keys that were cleared.
+         * @param key The key of the preference that was changed, added, or removed. Apps targeting
+         *            {@link android.os.Build.VERSION_CODES#R} on devices running OS versions
+         *            {@link android.os.Build.VERSION_CODES#R Android R} or later, will receive
+         *            a {@code null} value when preferences are cleared.
          */
-        void onSharedPreferencesClear(@NonNull SharedPreferences sharedPreferences,
-                @NonNull Set<String> keys);
+        void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key);
     }
 
     /**
@@ -405,35 +389,4 @@
      * @see #registerOnSharedPreferenceChangeListener
      */
     void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener);
-
-    /**
-     * Registers a callback to be invoked when preferences are cleared via {@link Editor#clear()}.
-     *
-     * <p class="caution"><strong>Caution:</strong> The preference manager does
-     * not currently store a strong reference to the listener. You must store a
-     * strong reference to the listener, or it will be susceptible to garbage
-     * collection. We recommend you keep a reference to the listener in the
-     * instance data of an object that will exist as long as you need the
-     * listener.</p>
-     *
-     * @param listener The callback that will run.
-     * @see #unregisterOnSharedPreferencesClearListener
-     */
-    default void registerOnSharedPreferencesClearListener(
-            @NonNull OnSharedPreferencesClearListener listener) {
-        throw new UnsupportedOperationException(
-                "registerOnSharedPreferencesClearListener not implemented");
-    }
-
-    /**
-     * Unregisters a previous callback for {@link Editor#clear()}.
-     *
-     * @param listener The callback that should be unregistered.
-     * @see #registerOnSharedPreferencesClearListener
-     */
-    default void unregisterOnSharedPreferencesClearListener(
-            @NonNull OnSharedPreferencesClearListener listener) {
-        throw new UnsupportedOperationException(
-                "unregisterOnSharedPreferencesClearListener not implemented");
-    }
 }
diff --git a/core/java/android/content/om/OverlayInfo.java b/core/java/android/content/om/OverlayInfo.java
index f39fc66..1a78f79 100644
--- a/core/java/android/content/om/OverlayInfo.java
+++ b/core/java/android/content/om/OverlayInfo.java
@@ -413,7 +413,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (this == obj) {
             return true;
         }
@@ -448,6 +448,7 @@
         return true;
     }
 
+    @NonNull
     @Override
     public String toString() {
         return "OverlayInfo { overlay=" + packageName + ", targetPackage=" + targetPackageName
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 037a149..c74daa8 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -503,9 +503,38 @@
     }
 
     /**
-     * Retrieves a list of launchable activities that match {@link Intent#ACTION_MAIN} and
-     * {@link Intent#CATEGORY_LAUNCHER}, for a specified user. Result may include
-     * synthesized activities like app details Activity injected by system.
+     * Retrieves a list of activities that specify {@link Intent#ACTION_MAIN} and
+     * {@link Intent#CATEGORY_LAUNCHER}, across all apps, for a specified user. If an app doesn't
+     * have any activities that specify <code>ACTION_MAIN</code> or <code>CATEGORY_LAUNCHER</code>,
+     * the system adds a synthesized activity to the list. This synthesized activity represents the
+     * app's details page within system settings.
+     *
+     * <p class="note"><b>Note: </b>It's possible for system apps, such as app stores, to prevent
+     * the system from adding synthesized activities to the returned list.</p>
+     *
+     * <p>As of <a href="/reference/android/os/Build.VERSION_CODES.html#Q">Android Q</a>, at least
+     * one of the app's activities or synthesized activities appears in the returned list unless the
+     * app satisfies at least one of the following conditions:</p>
+     * <ul>
+     * <li>The app is a system app.</li>
+     * <li>The app doesn't request any <a href="/guide/topics/permissions/overview">permissions</a>.
+     * </li>
+     * <li>The <code>&lt;application&gt;</code> tag in the app's manifest doesn't contain any child
+     * elements that represent
+     * <a href="/guide/components/fundamentals#DeclaringComponents">app components</a>.</li>
+     * </ul>
+     *
+     * <p>Additionally, the system hides synthesized activities for some or all apps in the
+     * following enterprise-related cases:</p>
+     * <ul>
+     * <li>If the device is a
+     * <a href="https://developers.google.com/android/work/overview#company-owned-devices-for-knowledge-workers">fully
+     * managed device</a>, no synthesized activities for any app appear in the returned list.</li>
+     * <li>If the current user has a
+     * <a href="https://developers.google.com/android/work/overview#employee-owned-devices-byod">work
+     * profile</a>, no synthesized activities for the user's work apps appear in the returned
+     * list.</li>
+     * </ul>
      *
      * @param packageName The specific package to query. If null, it checks all installed packages
      *            in the profile.
diff --git a/core/java/android/content/pm/SuspendDialogInfo.java b/core/java/android/content/pm/SuspendDialogInfo.java
index db8f8c2..73b75df 100644
--- a/core/java/android/content/pm/SuspendDialogInfo.java
+++ b/core/java/android/content/pm/SuspendDialogInfo.java
@@ -185,7 +185,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (this == obj) {
             return true;
         }
@@ -200,6 +200,7 @@
                 && Objects.equals(mDialogMessage, otherDialogInfo.mDialogMessage);
     }
 
+    @NonNull
     @Override
     public String toString() {
         final StringBuilder builder = new StringBuilder("SuspendDialogInfo: {");
diff --git a/core/java/android/content/rollback/RollbackManager.java b/core/java/android/content/rollback/RollbackManager.java
index 1609f53..73b8a48 100644
--- a/core/java/android/content/rollback/RollbackManager.java
+++ b/core/java/android/content/rollback/RollbackManager.java
@@ -74,10 +74,7 @@
     }
 
     /**
-     * Returns a list of all currently available rollbacks. This includes ones for very recently
-     * installed packages (even if onFinished has not yet been called). As a result, packages that
-     * very recently failed to install may also be included, but those rollbacks will fail with
-     * 'rollback not available'.
+     * Returns a list of all currently available rollbacks.
      *
      * @throws SecurityException if the caller does not have appropriate permissions.
      */
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
index 3e130c5..c28cf8f 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
@@ -129,7 +129,7 @@
         public CameraLooper(int cameraId) {
             mCameraId = cameraId;
 
-            mThread = new Thread(this);
+            mThread = new Thread(this, "LegacyCameraLooper");
             mThread.start();
         }
 
diff --git a/core/java/android/hardware/display/AmbientBrightnessDayStats.java b/core/java/android/hardware/display/AmbientBrightnessDayStats.java
index b25ef8d..350bc30d 100644
--- a/core/java/android/hardware/display/AmbientBrightnessDayStats.java
+++ b/core/java/android/hardware/display/AmbientBrightnessDayStats.java
@@ -17,6 +17,7 @@
 package android.hardware.display;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.os.Parcel;
@@ -136,7 +137,7 @@
             };
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (this == obj) {
             return true;
         }
@@ -161,6 +162,7 @@
         return result;
     }
 
+    @NonNull
     @Override
     public String toString() {
         StringBuilder bucketBoundariesString = new StringBuilder();
diff --git a/core/java/android/hardware/display/BrightnessConfiguration.java b/core/java/android/hardware/display/BrightnessConfiguration.java
index 5b63dcf..4c2e297 100644
--- a/core/java/android/hardware/display/BrightnessConfiguration.java
+++ b/core/java/android/hardware/display/BrightnessConfiguration.java
@@ -145,6 +145,7 @@
         return 0;
     }
 
+    @NonNull
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder("BrightnessConfiguration{[");
@@ -184,7 +185,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (o == this) {
             return true;
         }
diff --git a/core/java/android/hardware/display/BrightnessCorrection.java b/core/java/android/hardware/display/BrightnessCorrection.java
index b029acc..22df778 100644
--- a/core/java/android/hardware/display/BrightnessCorrection.java
+++ b/core/java/android/hardware/display/BrightnessCorrection.java
@@ -18,6 +18,7 @@
 
 import android.annotation.FloatRange;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.os.Parcel;
@@ -98,13 +99,13 @@
      *
      * @return A string representation.
      */
+    @NonNull
     public String toString() {
         return mImplementation.toString();
     }
 
-
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (o == this) {
             return true;
         }
diff --git a/core/java/android/hardware/hdmi/HdmiDeviceInfo.java b/core/java/android/hardware/hdmi/HdmiDeviceInfo.java
index 1362116..55b0726 100644
--- a/core/java/android/hardware/hdmi/HdmiDeviceInfo.java
+++ b/core/java/android/hardware/hdmi/HdmiDeviceInfo.java
@@ -16,6 +16,8 @@
 
 package android.hardware.hdmi;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -458,6 +460,7 @@
         }
     }
 
+    @NonNull
     @Override
     public String toString() {
         StringBuffer s = new StringBuffer();
@@ -493,7 +496,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (!(obj instanceof HdmiDeviceInfo)) {
             return false;
         }
diff --git a/core/java/android/hardware/hdmi/HdmiPortInfo.java b/core/java/android/hardware/hdmi/HdmiPortInfo.java
index f53f458..2623458 100644
--- a/core/java/android/hardware/hdmi/HdmiPortInfo.java
+++ b/core/java/android/hardware/hdmi/HdmiPortInfo.java
@@ -15,6 +15,8 @@
  */
 package android.hardware.hdmi;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -162,6 +164,7 @@
         dest.writeInt(mMhlSupported ? 1 : 0);
     }
 
+    @NonNull
     @Override
     public String toString() {
         StringBuffer s = new StringBuffer();
@@ -175,7 +178,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (!(o instanceof HdmiPortInfo)) {
             return false;
         }
diff --git a/core/java/android/hardware/location/ContextHubInfo.java b/core/java/android/hardware/location/ContextHubInfo.java
index b5da381..a11f2e9 100644
--- a/core/java/android/hardware/location/ContextHubInfo.java
+++ b/core/java/android/hardware/location/ContextHubInfo.java
@@ -15,6 +15,7 @@
  */
 package android.hardware.location;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.hardware.contexthub.V1_0.ContextHub;
@@ -248,6 +249,7 @@
         return mChrePatchVersion;
     }
 
+    @NonNull
     @Override
     public String toString() {
         String retVal = "";
diff --git a/core/java/android/hardware/location/ContextHubIntentEvent.java b/core/java/android/hardware/location/ContextHubIntentEvent.java
index d1190ab..754327a 100644
--- a/core/java/android/hardware/location/ContextHubIntentEvent.java
+++ b/core/java/android/hardware/location/ContextHubIntentEvent.java
@@ -192,6 +192,7 @@
         return mNanoAppMessage;
     }
 
+    @NonNull
     @Override
     public String toString() {
         String out = "ContextHubIntentEvent[eventType = " + mEventType
diff --git a/core/java/android/hardware/location/ContextHubMessage.java b/core/java/android/hardware/location/ContextHubMessage.java
index 1c98427..6777c53 100644
--- a/core/java/android/hardware/location/ContextHubMessage.java
+++ b/core/java/android/hardware/location/ContextHubMessage.java
@@ -16,6 +16,7 @@
 
 package android.hardware.location;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -127,7 +128,7 @@
         out.writeByteArray(mData);
     }
 
-    public static final @android.annotation.NonNull Parcelable.Creator<ContextHubMessage> CREATOR
+    public static final @NonNull Parcelable.Creator<ContextHubMessage> CREATOR
             = new Parcelable.Creator<ContextHubMessage>() {
         public ContextHubMessage createFromParcel(Parcel in) {
             return new ContextHubMessage(in);
@@ -138,6 +139,7 @@
         }
     };
 
+    @NonNull
     @Override
     public String toString() {
         int length = mData.length;
diff --git a/core/java/android/hardware/location/GeofenceHardwareMonitorEvent.java b/core/java/android/hardware/location/GeofenceHardwareMonitorEvent.java
index fbbf687..78cca96 100644
--- a/core/java/android/hardware/location/GeofenceHardwareMonitorEvent.java
+++ b/core/java/android/hardware/location/GeofenceHardwareMonitorEvent.java
@@ -16,6 +16,7 @@
 
 package android.hardware.location;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.location.Location;
 import android.os.Parcel;
@@ -72,7 +73,7 @@
         return mLocation;
     }
 
-    public static final @android.annotation.NonNull Creator<GeofenceHardwareMonitorEvent> CREATOR =
+    public static final @NonNull Creator<GeofenceHardwareMonitorEvent> CREATOR =
             new Creator<GeofenceHardwareMonitorEvent>() {
                 @Override
                 public GeofenceHardwareMonitorEvent createFromParcel(Parcel source) {
@@ -108,6 +109,7 @@
         parcel.writeParcelable(mLocation, flags);
     }
 
+    @NonNull
     @Override
     public String toString() {
         return String.format(
diff --git a/core/java/android/hardware/location/MemoryRegion.java b/core/java/android/hardware/location/MemoryRegion.java
index ecd369a..c033228 100644
--- a/core/java/android/hardware/location/MemoryRegion.java
+++ b/core/java/android/hardware/location/MemoryRegion.java
@@ -16,6 +16,7 @@
 
 package android.hardware.location;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
@@ -79,6 +80,7 @@
         return mIsExecutable;
     }
 
+    @NonNull
     @Override
     public String toString() {
         String mask = "";
diff --git a/core/java/android/hardware/location/NanoApp.java b/core/java/android/hardware/location/NanoApp.java
index 3fbb069..6a734f3 100644
--- a/core/java/android/hardware/location/NanoApp.java
+++ b/core/java/android/hardware/location/NanoApp.java
@@ -15,6 +15,7 @@
  */
 package android.hardware.location;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -370,6 +371,7 @@
         }
     };
 
+    @NonNull
     @Override
     public String toString() {
         String retVal = "Id : " + mAppId;
diff --git a/core/java/android/hardware/location/NanoAppFilter.java b/core/java/android/hardware/location/NanoAppFilter.java
index 0700dd1..1d8b69d 100644
--- a/core/java/android/hardware/location/NanoAppFilter.java
+++ b/core/java/android/hardware/location/NanoAppFilter.java
@@ -16,6 +16,7 @@
 
 package android.hardware.location;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -131,6 +132,7 @@
                 (versionsMatch(mVersionRestrictionMask, mAppVersion, info.getAppVersion()));
     }
 
+    @NonNull
     @Override
     public String toString() {
         return "nanoAppId: 0x" + Long.toHexString(mAppId)
diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.java b/core/java/android/hardware/location/NanoAppInstanceInfo.java
index a6c754d..ea11756 100644
--- a/core/java/android/hardware/location/NanoAppInstanceInfo.java
+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.java
@@ -219,6 +219,7 @@
         }
     };
 
+    @NonNull
     @Override
     public String toString() {
         String retVal = "handle : " + mHandle;
diff --git a/core/java/android/hardware/location/NanoAppMessage.java b/core/java/android/hardware/location/NanoAppMessage.java
index 078532a..bb3e81a 100644
--- a/core/java/android/hardware/location/NanoAppMessage.java
+++ b/core/java/android/hardware/location/NanoAppMessage.java
@@ -15,6 +15,7 @@
  */
 package android.hardware.location;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
@@ -136,7 +137,7 @@
         out.writeByteArray(mMessageBody);
     }
 
-    public static final @android.annotation.NonNull Creator<NanoAppMessage> CREATOR =
+    public static final @NonNull Creator<NanoAppMessage> CREATOR =
             new Creator<NanoAppMessage>() {
                 @Override
                 public NanoAppMessage createFromParcel(Parcel in) {
@@ -149,6 +150,7 @@
                 }
             };
 
+    @NonNull
     @Override
     public String toString() {
         int length = mMessageBody.length;
diff --git a/core/java/android/hardware/radio/ProgramList.java b/core/java/android/hardware/radio/ProgramList.java
index f4fd1b6..ec318b7 100644
--- a/core/java/android/hardware/radio/ProgramList.java
+++ b/core/java/android/hardware/radio/ProgramList.java
@@ -377,7 +377,7 @@
         }
 
         @Override
-        public boolean equals(Object obj) {
+        public boolean equals(@Nullable Object obj) {
             if (this == obj) return true;
             if (!(obj instanceof Filter)) return false;
             Filter other = (Filter) obj;
@@ -389,6 +389,7 @@
             return true;
         }
 
+        @NonNull
         @Override
         public String toString() {
             return "Filter [mIdentifierTypes=" + mIdentifierTypes
diff --git a/core/java/android/hardware/radio/ProgramSelector.java b/core/java/android/hardware/radio/ProgramSelector.java
index b321855..d525753 100644
--- a/core/java/android/hardware/radio/ProgramSelector.java
+++ b/core/java/android/hardware/radio/ProgramSelector.java
@@ -485,6 +485,7 @@
         return new ProgramSelector(programType, primary, secondary, null);
     }
 
+    @NonNull
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder("ProgramSelector(type=").append(mProgramType)
@@ -502,7 +503,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (this == obj) return true;
         if (!(obj instanceof ProgramSelector)) return false;
         ProgramSelector other = (ProgramSelector) obj;
@@ -611,6 +612,7 @@
             return mValue;
         }
 
+        @NonNull
         @Override
         public String toString() {
             return "Identifier(" + mType + ", " + mValue + ")";
@@ -622,7 +624,7 @@
         }
 
         @Override
-        public boolean equals(Object obj) {
+        public boolean equals(@Nullable Object obj) {
             if (this == obj) return true;
             if (!(obj instanceof Identifier)) return false;
             Identifier other = (Identifier) obj;
diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java
index a7ff644..6ea2ac4 100644
--- a/core/java/android/hardware/radio/RadioManager.java
+++ b/core/java/android/hardware/radio/RadioManager.java
@@ -485,6 +485,7 @@
             return 0;
         }
 
+        @NonNull
         @Override
         public String toString() {
             return "ModuleProperties [mId=" + mId
@@ -507,7 +508,7 @@
         }
 
         @Override
-        public boolean equals(Object obj) {
+        public boolean equals(@Nullable Object obj) {
             if (this == obj) return true;
             if (!(obj instanceof ModuleProperties)) return false;
             ModuleProperties other = (ModuleProperties) obj;
@@ -660,6 +661,7 @@
             return 0;
         }
 
+        @NonNull
         @Override
         public String toString() {
             return "BandDescriptor [mRegion=" + mRegion + ", mType=" + mType + ", mLowerLimit="
@@ -679,7 +681,7 @@
         }
 
         @Override
-        public boolean equals(Object obj) {
+        public boolean equals(@Nullable Object obj) {
             if (this == obj)
                 return true;
             if (!(obj instanceof BandDescriptor))
@@ -788,6 +790,7 @@
             return 0;
         }
 
+        @NonNull
         @Override
         public String toString() {
             return "FmBandDescriptor [ "+ super.toString() + " mStereo=" + mStereo
@@ -808,7 +811,7 @@
         }
 
         @Override
-        public boolean equals(Object obj) {
+        public boolean equals(@Nullable Object obj) {
             if (this == obj)
                 return true;
             if (!super.equals(obj))
@@ -877,6 +880,7 @@
             return 0;
         }
 
+        @NonNull
         @Override
         public String toString() {
             return "AmBandDescriptor [ "+ super.toString() + " mStereo=" + mStereo + "]";
@@ -891,7 +895,7 @@
         }
 
         @Override
-        public boolean equals(Object obj) {
+        public boolean equals(@Nullable Object obj) {
             if (this == obj)
                 return true;
             if (!super.equals(obj))
@@ -997,6 +1001,7 @@
             return 0;
         }
 
+        @NonNull
         @Override
         public String toString() {
             return "BandConfig [ " + mDescriptor.toString() + "]";
@@ -1011,7 +1016,7 @@
         }
 
         @Override
-        public boolean equals(Object obj) {
+        public boolean equals(@Nullable Object obj) {
             if (this == obj)
                 return true;
             if (!(obj instanceof BandConfig))
@@ -1125,6 +1130,7 @@
             return 0;
         }
 
+        @NonNull
         @Override
         public String toString() {
             return "FmBandConfig [" + super.toString()
@@ -1145,7 +1151,7 @@
         }
 
         @Override
-        public boolean equals(Object obj) {
+        public boolean equals(@Nullable Object obj) {
             if (this == obj)
                 return true;
             if (!super.equals(obj))
@@ -1317,6 +1323,7 @@
             return 0;
         }
 
+        @NonNull
         @Override
         public String toString() {
             return "AmBandConfig [" + super.toString()
@@ -1332,7 +1339,7 @@
         }
 
         @Override
-        public boolean equals(Object obj) {
+        public boolean equals(@Nullable Object obj) {
             if (this == obj)
                 return true;
             if (!super.equals(obj))
@@ -1656,6 +1663,7 @@
             return 0;
         }
 
+        @NonNull
         @Override
         public String toString() {
             return "ProgramInfo"
@@ -1676,7 +1684,7 @@
         }
 
         @Override
-        public boolean equals(Object obj) {
+        public boolean equals(@Nullable Object obj) {
             if (this == obj) return true;
             if (!(obj instanceof ProgramInfo)) return false;
             ProgramInfo other = (ProgramInfo) obj;
diff --git a/core/java/android/hardware/radio/RadioMetadata.java b/core/java/android/hardware/radio/RadioMetadata.java
index 76304bd..a882c2f 100644
--- a/core/java/android/hardware/radio/RadioMetadata.java
+++ b/core/java/android/hardware/radio/RadioMetadata.java
@@ -16,6 +16,7 @@
 package android.hardware.radio;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
@@ -279,7 +280,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (this == obj) return true;
         if (!(obj instanceof RadioMetadata)) return false;
         Bundle otherBundle = ((RadioMetadata) obj).mBundle;
@@ -308,6 +309,7 @@
         mBundle = in.readBundle();
     }
 
+    @NonNull
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder("RadioMetadata[");
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index 5b5bd76..f96f47d 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -22,6 +22,7 @@
 import static android.system.OsConstants.EPERM;
 import static android.system.OsConstants.EPIPE;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
@@ -829,7 +830,7 @@
         }
 
         @Override
-        public boolean equals(Object obj) {
+        public boolean equals(@Nullable Object obj) {
             if (this == obj)
                 return true;
             if (obj == null)
@@ -869,6 +870,7 @@
             return true;
         }
 
+        @NonNull
         @Override
         public String toString() {
             return "RecognitionEvent [status=" + status + ", soundModelHandle=" + soundModelHandle
diff --git a/core/java/android/hardware/usb/UsbPort.java b/core/java/android/hardware/usb/UsbPort.java
index c674480..506230e 100644
--- a/core/java/android/hardware/usb/UsbPort.java
+++ b/core/java/android/hardware/usb/UsbPort.java
@@ -327,7 +327,7 @@
         return false;
     }
 
-
+    @NonNull
     @Override
     public String toString() {
         return "UsbPort{id=" + mId + ", supportedModes=" + modeToString(mSupportedModes)
diff --git a/core/java/android/hardware/usb/UsbPortStatus.java b/core/java/android/hardware/usb/UsbPortStatus.java
index 5e9a410..43c418e 100644
--- a/core/java/android/hardware/usb/UsbPortStatus.java
+++ b/core/java/android/hardware/usb/UsbPortStatus.java
@@ -17,6 +17,7 @@
 package android.hardware.usb;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.hardware.usb.V1_0.Constants;
 import android.os.Parcel;
@@ -322,6 +323,7 @@
         return mContaminantProtectionStatus;
     }
 
+    @NonNull
     @Override
     public String toString() {
         return "UsbPortStatus{connected=" + isConnected()
@@ -352,7 +354,7 @@
         dest.writeInt(mContaminantDetectionStatus);
     }
 
-    public static final @android.annotation.NonNull Parcelable.Creator<UsbPortStatus> CREATOR =
+    public static final @NonNull Parcelable.Creator<UsbPortStatus> CREATOR =
             new Parcelable.Creator<UsbPortStatus>() {
         @Override
         public UsbPortStatus createFromParcel(Parcel in) {
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 82d4d1d..83391f3 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -19,6 +19,7 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -62,6 +63,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewRootImpl;
 import android.view.ViewTreeObserver;
 import android.view.Window;
 import android.view.WindowManager;
@@ -595,12 +597,12 @@
             if (DEBUG) Log.v(TAG, "hideSoftInput()");
             final boolean wasVisible = mIsPreRendered
                     ? mDecorViewVisible && mWindowVisible : isInputViewShown();
+            applyVisibilityInInsetsConsumerIfNecessary(false /* setVisible */);
             if (mIsPreRendered) {
                 if (DEBUG) {
                     Log.v(TAG, "Making IME window invisible");
                 }
                 setImeWindowStatus(IME_ACTIVE | IME_INVISIBLE, mBackDisposition);
-                applyVisibilityInInsetsConsumer(false /* setVisible */);
                 onPreRenderedWindowVisibilityChanged(false /* setVisible */);
             } else {
                 mShowInputFlags = 0;
@@ -632,11 +634,11 @@
                     if (DEBUG) {
                         Log.v(TAG, "Making IME window visible");
                     }
-                    applyVisibilityInInsetsConsumer(true /* setVisible */);
                     onPreRenderedWindowVisibilityChanged(true /* setVisible */);
                 } else {
                     showWindow(true);
                 }
+                applyVisibilityInInsetsConsumerIfNecessary(true /* setVisible */);
             }
             // If user uses hard keyboard, IME button should always be shown.
             setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
@@ -1974,16 +1976,20 @@
 
     /**
      * Apply the IME visibility in {@link android.view.ImeInsetsSourceConsumer} when
-     * pre-rendering is enabled.
+     * {@link ViewRootImpl.sNewInsetsMode} is enabled.
      * @param setVisible {@code true} to make it visible, false to hide it.
      */
-    private void applyVisibilityInInsetsConsumer(boolean setVisible) {
-        if (!mIsPreRendered) {
+    private void applyVisibilityInInsetsConsumerIfNecessary(boolean setVisible) {
+        if (!isVisibilityAppliedUsingInsetsConsumer()) {
             return;
         }
         mPrivOps.applyImeVisibility(setVisible);
     }
 
+    private boolean isVisibilityAppliedUsingInsetsConsumer() {
+        return ViewRootImpl.sNewInsetsMode > NEW_INSETS_MODE_NONE;
+    }
+
     private void finishViews(boolean finishingInput) {
         if (mInputViewStarted) {
             if (DEBUG) Log.v(TAG, "CALL: onFinishInputView");
@@ -2007,7 +2013,11 @@
         mWindowVisible = false;
         finishViews(false /* finishingInput */);
         if (mDecorViewVisible) {
-            mWindow.hide();
+            // When insets API is enabled, it is responsible for client and server side
+            // visibility of IME window.
+            if (!isVisibilityAppliedUsingInsetsConsumer()) {
+                mWindow.hide();
+            }
             mDecorViewVisible = false;
             onWindowHidden();
             mDecorViewWasVisible = false;
diff --git a/core/java/android/net/INetworkPolicyListener.aidl b/core/java/android/net/INetworkPolicyListener.aidl
index 10667ae..106b7be 100644
--- a/core/java/android/net/INetworkPolicyListener.aidl
+++ b/core/java/android/net/INetworkPolicyListener.aidl
@@ -22,5 +22,5 @@
     void onMeteredIfacesChanged(in String[] meteredIfaces);
     void onRestrictBackgroundChanged(boolean restrictBackground);
     void onUidPoliciesChanged(int uid, int uidPolicies);
-    void onSubscriptionOverride(int subId, int overrideMask, int overrideValue);
+    void onSubscriptionOverride(int subId, int overrideMask, int overrideValue, long networkTypeMask);
 }
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 385cb1d..90327663 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -76,7 +76,7 @@
     SubscriptionPlan[] getSubscriptionPlans(int subId, String callingPackage);
     void setSubscriptionPlans(int subId, in SubscriptionPlan[] plans, String callingPackage);
     String getSubscriptionPlansOwner(int subId);
-    void setSubscriptionOverride(int subId, int overrideMask, int overrideValue, long timeoutMillis, String callingPackage);
+    void setSubscriptionOverride(int subId, int overrideMask, int overrideValue, long networkTypeMask, long timeoutMillis, String callingPackage);
 
     void factoryReset(String subscriber);
 
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index 83813da..45d0c73 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -861,6 +861,7 @@
             return mResourceId;
         }
 
+        @NonNull
         @Override
         public String toString() {
             return new StringBuilder()
diff --git a/core/java/android/net/NetworkKey.java b/core/java/android/net/NetworkKey.java
index 0a9a3c8..a101da7 100644
--- a/core/java/android/net/NetworkKey.java
+++ b/core/java/android/net/NetworkKey.java
@@ -16,6 +16,7 @@
 
 package android.net;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.net.wifi.ScanResult;
@@ -152,7 +153,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
 
@@ -166,6 +167,7 @@
         return Objects.hash(type, wifiKey);
     }
 
+    @NonNull
     @Override
     public String toString() {
         switch (type) {
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index bf27262..628dcd2 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -380,6 +380,7 @@
         @Override public void onMeteredIfacesChanged(String[] meteredIfaces) { }
         @Override public void onRestrictBackgroundChanged(boolean restrictBackground) { }
         @Override public void onUidPoliciesChanged(int uid, int uidPolicies) { }
-        @Override public void onSubscriptionOverride(int subId, int overrideMask, int overrideValue) { }
+        @Override public void onSubscriptionOverride(int subId, int overrideMask, int overrideValue,
+                long networkTypeMask) { }
     }
 }
diff --git a/core/java/android/net/RssiCurve.java b/core/java/android/net/RssiCurve.java
index a173b0c..668e966 100644
--- a/core/java/android/net/RssiCurve.java
+++ b/core/java/android/net/RssiCurve.java
@@ -16,6 +16,8 @@
 
 package android.net;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -170,7 +172,7 @@
      * not considered equal to each other.
      */
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
 
@@ -187,6 +189,7 @@
         return Objects.hash(start, bucketWidth, activeNetworkRssiBoost) ^ Arrays.hashCode(rssiBuckets);
     }
 
+    @NonNull
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
diff --git a/core/java/android/net/ScoredNetwork.java b/core/java/android/net/ScoredNetwork.java
index effc1aa..64b3bf1 100644
--- a/core/java/android/net/ScoredNetwork.java
+++ b/core/java/android/net/ScoredNetwork.java
@@ -16,6 +16,7 @@
 
 package android.net;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Bundle;
@@ -182,7 +183,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
 
@@ -220,6 +221,7 @@
         return Objects.hash(networkKey, rssiCurve, meteredHint, attributes);
     }
 
+    @NonNull
     @Override
     public String toString() {
         StringBuilder out = new StringBuilder(
diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java
index d6deba5..5bc9953 100644
--- a/core/java/android/net/StaticIpConfiguration.java
+++ b/core/java/android/net/StaticIpConfiguration.java
@@ -236,6 +236,7 @@
         return lp;
     }
 
+    @NonNull
     @Override
     public String toString() {
         StringBuffer str = new StringBuffer();
@@ -267,7 +268,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (this == obj) return true;
 
         if (!(obj instanceof StaticIpConfiguration)) return false;
diff --git a/core/java/android/net/WebAddress.java b/core/java/android/net/WebAddress.java
index fbc281f..994c794 100644
--- a/core/java/android/net/WebAddress.java
+++ b/core/java/android/net/WebAddress.java
@@ -18,6 +18,7 @@
 
 import static android.util.Patterns.GOOD_IRI_CHAR;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Build;
@@ -132,6 +133,7 @@
         if (mScheme.equals("")) mScheme = "http";
     }
 
+    @NonNull
     @Override
     public String toString() {
         String port = "";
diff --git a/core/java/android/net/WifiKey.java b/core/java/android/net/WifiKey.java
index e3a93a8..bc9d8c5 100644
--- a/core/java/android/net/WifiKey.java
+++ b/core/java/android/net/WifiKey.java
@@ -16,6 +16,8 @@
 
 package android.net;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -91,7 +93,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
 
@@ -105,6 +107,7 @@
         return Objects.hash(ssid, bssid);
     }
 
+    @NonNull
     @Override
     public String toString() {
         return "WifiKey[SSID=" + ssid + ",BSSID=" + bssid + "]";
diff --git a/core/java/android/net/apf/ApfCapabilities.java b/core/java/android/net/apf/ApfCapabilities.java
index 4dd2ace..b1de74e 100644
--- a/core/java/android/net/apf/ApfCapabilities.java
+++ b/core/java/android/net/apf/ApfCapabilities.java
@@ -17,6 +17,7 @@
 package android.net.apf;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.content.res.Resources;
@@ -91,6 +92,7 @@
         }
     };
 
+    @NonNull
     @Override
     public String toString() {
         return String.format("%s{version: %d, maxSize: %d, format: %d}", getClass().getSimpleName(),
@@ -98,7 +100,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (!(obj instanceof  ApfCapabilities)) return false;
         final ApfCapabilities other = (ApfCapabilities) obj;
         return apfVersionSupported == other.apfVersionSupported
diff --git a/core/java/android/net/metrics/ApfProgramEvent.java b/core/java/android/net/metrics/ApfProgramEvent.java
index e9c209c..8243be9 100644
--- a/core/java/android/net/metrics/ApfProgramEvent.java
+++ b/core/java/android/net/metrics/ApfProgramEvent.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
@@ -185,6 +186,7 @@
         return 0;
     }
 
+    @NonNull
     @Override
     public String toString() {
         String lifetimeString = (lifetime < Long.MAX_VALUE) ? lifetime + "s" : "forever";
@@ -193,7 +195,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (obj == null || !(obj.getClass().equals(ApfProgramEvent.class))) return false;
         final ApfProgramEvent other = (ApfProgramEvent) obj;
         return lifetime == other.lifetime
diff --git a/core/java/android/net/metrics/ApfStats.java b/core/java/android/net/metrics/ApfStats.java
index b963777..eac5579f 100644
--- a/core/java/android/net/metrics/ApfStats.java
+++ b/core/java/android/net/metrics/ApfStats.java
@@ -17,6 +17,7 @@
 package android.net.metrics;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
@@ -260,6 +261,7 @@
         return 0;
     }
 
+    @NonNull
     @Override
     public String toString() {
         return new StringBuilder("ApfStats(")
@@ -276,7 +278,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (obj == null || !(obj.getClass().equals(ApfStats.class))) return false;
         final ApfStats other = (ApfStats) obj;
         return durationMs == other.durationMs
diff --git a/core/java/android/net/metrics/DhcpClientEvent.java b/core/java/android/net/metrics/DhcpClientEvent.java
index 2fed736..5f9f507 100644
--- a/core/java/android/net/metrics/DhcpClientEvent.java
+++ b/core/java/android/net/metrics/DhcpClientEvent.java
@@ -17,6 +17,7 @@
 package android.net.metrics;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
@@ -97,13 +98,14 @@
         return 0;
     }
 
+    @NonNull
     @Override
     public String toString() {
         return String.format("DhcpClientEvent(%s, %dms)", msg, durationMs);
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (obj == null || !(obj.getClass().equals(DhcpClientEvent.class))) return false;
         final DhcpClientEvent other = (DhcpClientEvent) obj;
         return TextUtils.equals(msg, other.msg)
diff --git a/core/java/android/net/metrics/DhcpErrorEvent.java b/core/java/android/net/metrics/DhcpErrorEvent.java
index 8760004..32efb5a 100644
--- a/core/java/android/net/metrics/DhcpErrorEvent.java
+++ b/core/java/android/net/metrics/DhcpErrorEvent.java
@@ -16,6 +16,7 @@
 
 package android.net.metrics;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.os.Parcel;
@@ -108,6 +109,7 @@
         return (0xFFFF0000 & errorCode) | (0xFF & option);
     }
 
+    @NonNull
     @Override
     public String toString() {
         return String.format("DhcpErrorEvent(%s)", Decoder.constants.get(errorCode));
diff --git a/core/java/android/net/metrics/IpManagerEvent.java b/core/java/android/net/metrics/IpManagerEvent.java
index ba05c59..f14abb8 100644
--- a/core/java/android/net/metrics/IpManagerEvent.java
+++ b/core/java/android/net/metrics/IpManagerEvent.java
@@ -17,6 +17,8 @@
 package android.net.metrics;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.os.Parcel;
@@ -95,6 +97,7 @@
         }
     };
 
+    @NonNull
     @Override
     public String toString() {
         return String.format("IpManagerEvent(%s, %dms)",
@@ -102,7 +105,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (obj == null || !(obj.getClass().equals(IpManagerEvent.class))) return false;
         final IpManagerEvent other = (IpManagerEvent) obj;
         return eventType == other.eventType
diff --git a/core/java/android/net/metrics/IpReachabilityEvent.java b/core/java/android/net/metrics/IpReachabilityEvent.java
index d4ba294..79e01d7 100644
--- a/core/java/android/net/metrics/IpReachabilityEvent.java
+++ b/core/java/android/net/metrics/IpReachabilityEvent.java
@@ -16,6 +16,8 @@
 
 package android.net.metrics;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.os.Parcel;
@@ -85,6 +87,7 @@
         }
     };
 
+    @NonNull
     @Override
     public String toString() {
         int hi = eventType & 0xff00;
@@ -94,7 +97,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (obj == null || !(obj.getClass().equals(IpReachabilityEvent.class))) return false;
         final IpReachabilityEvent other = (IpReachabilityEvent) obj;
         return eventType == other.eventType;
diff --git a/core/java/android/net/metrics/NetworkEvent.java b/core/java/android/net/metrics/NetworkEvent.java
index 0c57ec6..fe603cf 100644
--- a/core/java/android/net/metrics/NetworkEvent.java
+++ b/core/java/android/net/metrics/NetworkEvent.java
@@ -17,6 +17,8 @@
 package android.net.metrics;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.os.Parcel;
@@ -115,6 +117,7 @@
         }
     };
 
+    @NonNull
     @Override
     public String toString() {
         return String.format("NetworkEvent(%s, %dms)",
@@ -122,7 +125,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (obj == null || !(obj.getClass().equals(NetworkEvent.class))) return false;
         final NetworkEvent other = (NetworkEvent) obj;
         return eventType == other.eventType
diff --git a/core/java/android/net/metrics/RaEvent.java b/core/java/android/net/metrics/RaEvent.java
index 3fd87c2..661f648 100644
--- a/core/java/android/net/metrics/RaEvent.java
+++ b/core/java/android/net/metrics/RaEvent.java
@@ -17,6 +17,7 @@
 package android.net.metrics;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.os.Parcel;
@@ -85,6 +86,7 @@
         return 0;
     }
 
+    @NonNull
     @Override
     public String toString() {
         return new StringBuilder("RaEvent(lifetimes: ")
@@ -98,7 +100,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (obj == null || !(obj.getClass().equals(RaEvent.class))) return false;
         final RaEvent other = (RaEvent) obj;
         return routerLifetime == other.routerLifetime
diff --git a/core/java/android/net/metrics/ValidationProbeEvent.java b/core/java/android/net/metrics/ValidationProbeEvent.java
index 1aaa50d..8fab64a 100644
--- a/core/java/android/net/metrics/ValidationProbeEvent.java
+++ b/core/java/android/net/metrics/ValidationProbeEvent.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.os.Parcel;
@@ -164,6 +165,7 @@
         return Decoder.constants.get(probeType & 0xff00, "UNKNOWN");
     }
 
+    @NonNull
     @Override
     public String toString() {
         return String.format("ValidationProbeEvent(%s:%d %s, %dms)",
@@ -171,7 +173,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (obj == null || !(obj.getClass().equals(ValidationProbeEvent.class))) return false;
         final ValidationProbeEvent other = (ValidationProbeEvent) obj;
         return durationMs == other.durationMs
diff --git a/core/java/android/net/util/MultinetworkPolicyTracker.java b/core/java/android/net/util/MultinetworkPolicyTracker.java
index f7e494d..4e88149 100644
--- a/core/java/android/net/util/MultinetworkPolicyTracker.java
+++ b/core/java/android/net/util/MultinetworkPolicyTracker.java
@@ -64,7 +64,7 @@
 
     private final Context mContext;
     private final Handler mHandler;
-    private final Runnable mReevaluateRunnable;
+    private final Runnable mAvoidBadWifiCallback;
     private final List<Uri> mSettingsUris;
     private final ContentResolver mResolver;
     private final SettingObserver mSettingObserver;
@@ -81,12 +81,7 @@
     public MultinetworkPolicyTracker(Context ctx, Handler handler, Runnable avoidBadWifiCallback) {
         mContext = ctx;
         mHandler = handler;
-        mReevaluateRunnable = () -> {
-            if (updateAvoidBadWifi() && avoidBadWifiCallback != null) {
-                avoidBadWifiCallback.run();
-            }
-            updateMeteredMultipathPreference();
-        };
+        mAvoidBadWifiCallback = avoidBadWifiCallback;
         mSettingsUris = Arrays.asList(
             Settings.Global.getUriFor(NETWORK_AVOID_BAD_WIFI),
             Settings.Global.getUriFor(NETWORK_METERED_MULTIPATH_PREFERENCE));
@@ -95,15 +90,15 @@
         mBroadcastReceiver = new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
-                reevaluate();
+                reevaluateInternal();
             }
         };
 
-        TelephonyManager.from(ctx).listen(new PhoneStateListener() {
+        TelephonyManager.from(ctx).listen(new PhoneStateListener(handler.getLooper()) {
             @Override
             public void onActiveDataSubscriptionIdChanged(int subId) {
                 mActiveSubId = subId;
-                reevaluate();
+                reevaluateInternal();
             }
         }, PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
 
@@ -119,7 +114,7 @@
         final IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
         mContext.registerReceiverAsUser(
-                mBroadcastReceiver, UserHandle.ALL, intentFilter, null, null);
+                mBroadcastReceiver, UserHandle.ALL, intentFilter, null, mHandler);
 
         reevaluate();
     }
@@ -164,7 +159,17 @@
 
     @VisibleForTesting
     public void reevaluate() {
-        mHandler.post(mReevaluateRunnable);
+        mHandler.post(this::reevaluateInternal);
+    }
+
+    /**
+     * Reevaluate the settings. Must be called on the handler thread.
+     */
+    private void reevaluateInternal() {
+        if (updateAvoidBadWifi() && mAvoidBadWifiCallback != null) {
+            mAvoidBadWifiCallback.run();
+        }
+        updateMeteredMultipathPreference();
     }
 
     public boolean updateAvoidBadWifi() {
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index 4675600..d9000e4 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -114,7 +114,7 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public ApduServiceInfo(ResolveInfo info, String description,
+    public ApduServiceInfo(ResolveInfo info, boolean onHost, String description,
             ArrayList<AidGroup> staticAidGroups, ArrayList<AidGroup> dynamicAidGroups,
             boolean requiresUnlock, int bannerResource, int uid,
             String settingsActivityName, String offHost, String staticOffHost) {
@@ -124,7 +124,7 @@
         this.mDynamicAidGroups = new HashMap<String, AidGroup>();
         this.mOffHostName = offHost;
         this.mStaticOffHostName = staticOffHost;
-        this.mOnHost = (offHost == null);
+        this.mOnHost = onHost;
         this.mRequiresDeviceUnlock = requiresUnlock;
         for (AidGroup aidGroup : staticAidGroups) {
             this.mStaticAidGroups.put(aidGroup.category, aidGroup);
@@ -570,7 +570,7 @@
             int bannerResource = source.readInt();
             int uid = source.readInt();
             String settingsActivityName = source.readString();
-            return new ApduServiceInfo(info, description, staticAidGroups,
+            return new ApduServiceInfo(info, onHost, description, staticAidGroups,
                     dynamicAidGroups, requiresUnlock, bannerResource, uid,
                     settingsActivityName, offHostName, staticOffHostName);
         }
diff --git a/core/java/android/os/BatterySaverPolicyConfig.java b/core/java/android/os/BatterySaverPolicyConfig.java
index 3801cbd..3f6ce4f 100644
--- a/core/java/android/os/BatterySaverPolicyConfig.java
+++ b/core/java/android/os/BatterySaverPolicyConfig.java
@@ -161,6 +161,7 @@
         dest.writeInt(mLocationMode);
     }
 
+    @NonNull
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 6178b2b..5533721 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -645,6 +645,17 @@
          * Called before onTransact.
          *
          * @return an object that will be passed back to #onTransactEnded (or null).
+         * @hide
+         */
+        @Nullable
+        default Object onTransactStarted(@NonNull IBinder binder, int transactionCode, int flags) {
+            return onTransactStarted(binder, transactionCode);
+        }
+
+        /**
+         * Called before onTransact.
+         *
+         * @return an object that will be passed back to #onTransactEnded (or null).
          */
         @Nullable
         Object onTransactStarted(@NonNull IBinder binder, int transactionCode);
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index 97c0a13..c74cef8 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -496,7 +496,7 @@
 
         if (transactListener != null) {
             final int origWorkSourceUid = Binder.getCallingWorkSourceUid();
-            session = transactListener.onTransactStarted(this, code);
+            session = transactListener.onTransactStarted(this, code, flags);
 
             // Allow the listener to update the work source uid. We need to update the request
             // header if the uid is updated.
diff --git a/core/java/android/os/IMaintenanceActivityListener.aidl b/core/java/android/os/IMaintenanceActivityListener.aidl
deleted file mode 100644
index 6a2581f..0000000
--- a/core/java/android/os/IMaintenanceActivityListener.aidl
+++ /dev/null
@@ -1,22 +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 android.os;
-
-/** @hide */
-oneway interface IMaintenanceActivityListener {
-    void onMaintenanceActivityChanged(boolean active);
-}
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 1351380..9b8a40a 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -150,6 +150,14 @@
     void startTethering(in String[] dhcpRanges);
 
     /**
+     * Start tethering services with the specified dhcp server range and
+     * DNS proxy config.
+     * {@code boolean} is used to control legacy DNS proxy server.
+     * {@code String[]} is a set of start end pairs defining the ranges.
+     */
+    void startTetheringWithConfiguration(boolean usingLegacyDnsProxy, in String[] dhcpRanges);
+
+    /**
      * Stop currently running tethering services
      */
     @UnsupportedAppUsage
diff --git a/core/java/android/os/IncidentManager.java b/core/java/android/os/IncidentManager.java
index a94fd65..09e1c0f 100644
--- a/core/java/android/os/IncidentManager.java
+++ b/core/java/android/os/IncidentManager.java
@@ -255,7 +255,7 @@
          * @inheritDoc
          */
         @Override
-        public boolean equals(Object obj) {
+        public boolean equals(@Nullable Object obj) {
             if (this == obj) {
                 return true;
             }
diff --git a/core/java/android/os/IncidentReportArgs.java b/core/java/android/os/IncidentReportArgs.java
index a1f2430..7e858e1 100644
--- a/core/java/android/os/IncidentReportArgs.java
+++ b/core/java/android/os/IncidentReportArgs.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.os.Parcel;
@@ -117,6 +118,7 @@
     /**
      * Print this report as a string.
      */
+    @NonNull
     @Override
     public String toString() {
         final StringBuilder sb = new StringBuilder("Incident(");
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 2a4576a..271020d 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -616,10 +616,11 @@
     public static File getFile(FileDescriptor fd) throws IOException {
         try {
             final String path = Os.readlink("/proc/self/fd/" + fd.getInt$());
-            if (OsConstants.S_ISREG(Os.stat(path).st_mode)) {
+            if (OsConstants.S_ISREG(Os.stat(path).st_mode)
+                    || OsConstants.S_ISCHR(Os.stat(path).st_mode)) {
                 return new File(path);
             } else {
-                throw new IOException("Not a regular file: " + path);
+                throw new IOException("Not a regular file or character device: " + path);
             }
         } catch (ErrnoException e) {
             throw e.rethrowAsIOException();
diff --git a/core/java/android/os/ServiceSpecificException.java b/core/java/android/os/ServiceSpecificException.java
index 03d5d3e..49ce40b 100644
--- a/core/java/android/os/ServiceSpecificException.java
+++ b/core/java/android/os/ServiceSpecificException.java
@@ -15,6 +15,7 @@
  */
 package android.os;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 
@@ -44,6 +45,7 @@
         this.errorCode = errorCode;
     }
 
+    @NonNull
     @Override
     public String toString() {
         return super.toString() + " (code " + errorCode + ")";
diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java
index f302263..ddd949d 100644
--- a/core/java/android/os/UserManagerInternal.java
+++ b/core/java/android/os/UserManagerInternal.java
@@ -15,6 +15,7 @@
  */
 package android.os;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.content.Context;
@@ -231,4 +232,9 @@
      * found.
      */
     public abstract @Nullable UserInfo getUserInfo(@UserIdInt int userId);
+
+    /**
+     * Gets all {@link UserInfo UserInfos}.
+     */
+    public abstract @NonNull UserInfo[] getUserInfos();
 }
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index 702b41b..26da0a0 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -53,7 +53,7 @@
     public static final int MAX_AMPLITUDE = 255;
 
     /**
-     * A click effect.
+     * A click effect. Use this effect as a baseline, as it's the most common type of click effect.
      *
      * @see #get(int)
      */
@@ -67,7 +67,7 @@
     public static final int EFFECT_DOUBLE_CLICK = Effect.DOUBLE_CLICK;
 
     /**
-     * A tick effect.
+     * A tick effect. This effect is less strong compared to {@link #EFFECT_CLICK}.
      * @see #get(int)
      */
     public static final int EFFECT_TICK = Effect.TICK;
@@ -89,7 +89,7 @@
     public static final int EFFECT_POP = Effect.POP;
 
     /**
-     * A heavy click effect.
+     * A heavy click effect. This effect is stronger than {@link #EFFECT_CLICK}.
      * @see #get(int)
      */
     public static final int EFFECT_HEAVY_CLICK = Effect.HEAVY_CLICK;
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java
index 114de23..9cc9aac 100644
--- a/core/java/android/os/WorkSource.java
+++ b/core/java/android/os/WorkSource.java
@@ -1,5 +1,6 @@
 package android.os;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
@@ -205,7 +206,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (o instanceof WorkSource) {
             WorkSource other = (WorkSource) o;
 
@@ -989,6 +990,7 @@
             mTags = tags;
         }
 
+        @NonNull
         @Override
         public String toString() {
             StringBuilder result = new StringBuilder("WorkChain{");
@@ -1015,7 +1017,7 @@
         }
 
         @Override
-        public boolean equals(Object o) {
+        public boolean equals(@Nullable Object o) {
             if (o instanceof WorkChain) {
                 WorkChain other = (WorkChain) o;
 
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index 42816c0..5e35958 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -19,6 +19,7 @@
 import android.Manifest;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
@@ -144,7 +145,7 @@
         private final int mTargetSdk;
 
         @Override
-        public boolean equals(Object o) {
+        public boolean equals(@Nullable Object o) {
             if (this == o) return true;
             if (o == null || getClass() != o.getClass()) return false;
             SplitPermissionInfo that = (SplitPermissionInfo) o;
diff --git a/core/java/android/printservice/PrintServiceInfo.java b/core/java/android/printservice/PrintServiceInfo.java
index 565843e..0c1b61d 100644
--- a/core/java/android/printservice/PrintServiceInfo.java
+++ b/core/java/android/printservice/PrintServiceInfo.java
@@ -17,6 +17,7 @@
 package android.printservice;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.content.ComponentName;
 import android.content.Context;
@@ -292,7 +293,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (this == obj) {
             return true;
         }
@@ -313,6 +314,7 @@
         return true;
     }
 
+    @NonNull
     @Override
     public String toString() {
         StringBuilder builder = new StringBuilder();
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index b7676b6..4b9daf1 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -775,8 +775,9 @@
          *
          * @param namespace The namespace these properties belong to.
          * @param keyValueMap A map between property names and property values.
+         * @hide
          */
-        Properties(@NonNull String namespace, @Nullable Map<String, String> keyValueMap) {
+        public Properties(@NonNull String namespace, @Nullable Map<String, String> keyValueMap) {
             Preconditions.checkNotNull(namespace);
             mNamespace = namespace;
             mMap = new HashMap();
diff --git a/core/java/android/provider/SearchIndexableData.java b/core/java/android/provider/SearchIndexableData.java
index a60be53..87f9af3 100644
--- a/core/java/android/provider/SearchIndexableData.java
+++ b/core/java/android/provider/SearchIndexableData.java
@@ -16,6 +16,7 @@
 
 package android.provider;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.content.Context;
 
@@ -139,6 +140,7 @@
         context = ctx;
     }
 
+    @NonNull
     @Override
     public String toString() {
         final StringBuilder sb = new StringBuilder();
diff --git a/core/java/android/provider/SearchIndexableResource.java b/core/java/android/provider/SearchIndexableResource.java
index 1eb1734..0765b6b 100644
--- a/core/java/android/provider/SearchIndexableResource.java
+++ b/core/java/android/provider/SearchIndexableResource.java
@@ -16,6 +16,7 @@
 
 package android.provider;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.content.Context;
 
@@ -66,6 +67,7 @@
         super(context);
     }
 
+    @NonNull
     @Override
     public String toString() {
         final StringBuilder sb = new StringBuilder();
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f573d87..dd3942e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -16,20 +16,6 @@
 
 package android.provider;
 
-import static android.provider.settings.validators.SettingsValidators.ANY_INTEGER_VALIDATOR;
-import static android.provider.settings.validators.SettingsValidators.ANY_STRING_VALIDATOR;
-import static android.provider.settings.validators.SettingsValidators.BOOLEAN_VALIDATOR;
-import static android.provider.settings.validators.SettingsValidators.COMPONENT_NAME_VALIDATOR;
-import static android.provider.settings.validators.SettingsValidators.JSON_OBJECT_VALIDATOR;
-import static android.provider.settings.validators.SettingsValidators.LENIENT_IP_ADDRESS_VALIDATOR;
-import static android.provider.settings.validators.SettingsValidators.LOCALE_VALIDATOR;
-import static android.provider.settings.validators.SettingsValidators.NON_NEGATIVE_INTEGER_VALIDATOR;
-import static android.provider.settings.validators.SettingsValidators.NULLABLE_COMPONENT_NAME_VALIDATOR;
-import static android.provider.settings.validators.SettingsValidators.PACKAGE_NAME_VALIDATOR;
-import static android.provider.settings.validators.SettingsValidators.TILE_LIST_VALIDATOR;
-import static android.provider.settings.validators.SettingsValidators.TTS_LIST_VALIDATOR;
-import static android.provider.settings.validators.SettingsValidators.URI_VALIDATOR;
-
 import android.Manifest;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
@@ -63,9 +49,7 @@
 import android.content.res.Resources;
 import android.database.Cursor;
 import android.database.SQLException;
-import android.hardware.display.ColorDisplayManager;
 import android.location.LocationManager;
-import android.media.AudioFormat;
 import android.net.ConnectivityManager;
 import android.net.NetworkScoreManager;
 import android.net.Uri;
@@ -83,12 +67,6 @@
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
 import android.os.UserHandle;
-import android.provider.settings.validators.ComponentNameListValidator;
-import android.provider.settings.validators.DiscreteValueValidator;
-import android.provider.settings.validators.InclusiveFloatRangeValidator;
-import android.provider.settings.validators.InclusiveIntegerRangeValidator;
-import android.provider.settings.validators.PackageNameListValidator;
-import android.provider.settings.validators.Validator;
 import android.speech.tts.TextToSpeech;
 import android.telephony.SubscriptionManager;
 import android.text.TextUtils;
@@ -106,7 +84,6 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.net.URISyntaxException;
-import java.text.SimpleDateFormat;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Locale;
@@ -3120,30 +3097,6 @@
         @Deprecated
         public static final String STAY_ON_WHILE_PLUGGED_IN = Global.STAY_ON_WHILE_PLUGGED_IN;
 
-        private static final Validator STAY_ON_WHILE_PLUGGED_IN_VALIDATOR = new Validator() {
-            @Override
-            public boolean validate(String value) {
-                try {
-                    int val = Integer.parseInt(value);
-                    return (val == 0)
-                            || (val == BatteryManager.BATTERY_PLUGGED_AC)
-                            || (val == BatteryManager.BATTERY_PLUGGED_USB)
-                            || (val == BatteryManager.BATTERY_PLUGGED_WIRELESS)
-                            || (val == (BatteryManager.BATTERY_PLUGGED_AC
-                                    | BatteryManager.BATTERY_PLUGGED_USB))
-                            || (val == (BatteryManager.BATTERY_PLUGGED_AC
-                                    | BatteryManager.BATTERY_PLUGGED_WIRELESS))
-                            || (val == (BatteryManager.BATTERY_PLUGGED_USB
-                                    | BatteryManager.BATTERY_PLUGGED_WIRELESS))
-                            || (val == (BatteryManager.BATTERY_PLUGGED_AC
-                                    | BatteryManager.BATTERY_PLUGGED_USB
-                                    | BatteryManager.BATTERY_PLUGGED_WIRELESS));
-                } catch (NumberFormatException e) {
-                    return false;
-                }
-            }
-        };
-
         /**
          * What happens when the user presses the end call button if they're not
          * on a call.<br/>
@@ -3156,9 +3109,6 @@
          */
         public static final String END_BUTTON_BEHAVIOR = "end_button_behavior";
 
-        private static final Validator END_BUTTON_BEHAVIOR_VALIDATOR =
-                new InclusiveIntegerRangeValidator(0, 3);
-
         /**
          * END_BUTTON_BEHAVIOR value for "go home".
          * @hide
@@ -3183,8 +3133,6 @@
          */
         public static final String ADVANCED_SETTINGS = "advanced_settings";
 
-        private static final Validator ADVANCED_SETTINGS_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * ADVANCED_SETTINGS default value.
          * @hide
@@ -3285,8 +3233,6 @@
         @Deprecated
         public static final String WIFI_USE_STATIC_IP = "wifi_use_static_ip";
 
-        private static final Validator WIFI_USE_STATIC_IP_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * The static IP address.
          * <p>
@@ -3297,8 +3243,6 @@
         @Deprecated
         public static final String WIFI_STATIC_IP = "wifi_static_ip";
 
-        private static final Validator WIFI_STATIC_IP_VALIDATOR = LENIENT_IP_ADDRESS_VALIDATOR;
-
         /**
          * If using static IP, the gateway's IP address.
          * <p>
@@ -3309,8 +3253,6 @@
         @Deprecated
         public static final String WIFI_STATIC_GATEWAY = "wifi_static_gateway";
 
-        private static final Validator WIFI_STATIC_GATEWAY_VALIDATOR = LENIENT_IP_ADDRESS_VALIDATOR;
-
         /**
          * If using static IP, the net mask.
          * <p>
@@ -3321,8 +3263,6 @@
         @Deprecated
         public static final String WIFI_STATIC_NETMASK = "wifi_static_netmask";
 
-        private static final Validator WIFI_STATIC_NETMASK_VALIDATOR = LENIENT_IP_ADDRESS_VALIDATOR;
-
         /**
          * If using static IP, the primary DNS's IP address.
          * <p>
@@ -3333,8 +3273,6 @@
         @Deprecated
         public static final String WIFI_STATIC_DNS1 = "wifi_static_dns1";
 
-        private static final Validator WIFI_STATIC_DNS1_VALIDATOR = LENIENT_IP_ADDRESS_VALIDATOR;
-
         /**
          * If using static IP, the secondary DNS's IP address.
          * <p>
@@ -3345,8 +3283,6 @@
         @Deprecated
         public static final String WIFI_STATIC_DNS2 = "wifi_static_dns2";
 
-        private static final Validator WIFI_STATIC_DNS2_VALIDATOR = LENIENT_IP_ADDRESS_VALIDATOR;
-
         /**
          * Determines whether remote devices may discover and/or connect to
          * this device.
@@ -3358,9 +3294,6 @@
         public static final String BLUETOOTH_DISCOVERABILITY =
             "bluetooth_discoverability";
 
-        private static final Validator BLUETOOTH_DISCOVERABILITY_VALIDATOR =
-                new InclusiveIntegerRangeValidator(0, 2);
-
         /**
          * Bluetooth discoverability timeout.  If this value is nonzero, then
          * Bluetooth becomes discoverable for a certain number of seconds,
@@ -3369,9 +3302,6 @@
         public static final String BLUETOOTH_DISCOVERABILITY_TIMEOUT =
             "bluetooth_discoverability_timeout";
 
-        private static final Validator BLUETOOTH_DISCOVERABILITY_TIMEOUT_VALIDATOR =
-                NON_NEGATIVE_INTEGER_VALIDATOR;
-
         /**
          * @deprecated Use {@link android.provider.Settings.Secure#LOCK_PATTERN_ENABLED}
          * instead
@@ -3404,32 +3334,11 @@
         @Deprecated
         public static final String NEXT_ALARM_FORMATTED = "next_alarm_formatted";
 
-        private static final Validator NEXT_ALARM_FORMATTED_VALIDATOR = new Validator() {
-            private static final int MAX_LENGTH = 1000;
-
-            @Override
-            public boolean validate(String value) {
-                // TODO: No idea what the correct format is.
-                return value == null || value.length() < MAX_LENGTH;
-            }
-        };
-
         /**
          * Scaling factor for fonts, float.
          */
         public static final String FONT_SCALE = "font_scale";
 
-        private static final Validator FONT_SCALE_VALIDATOR = new Validator() {
-            @Override
-            public boolean validate(@Nullable String value) {
-                try {
-                    return Float.parseFloat(value) >= 0;
-                } catch (NumberFormatException | NullPointerException e) {
-                    return false;
-                }
-            }
-        };
-
         /**
          * The serialized system locale value.
          *
@@ -3466,34 +3375,12 @@
         @Deprecated
         public static final String DIM_SCREEN = "dim_screen";
 
-        private static final Validator DIM_SCREEN_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * The display color mode.
          * @hide
          */
         public static final String DISPLAY_COLOR_MODE = "display_color_mode";
 
-        private static final Validator DISPLAY_COLOR_MODE_VALIDATOR = new Validator() {
-            @Override
-            public boolean validate(@Nullable String value) {
-                // Assume the actual validation that this device can properly handle this kind of
-                // color mode further down in ColorDisplayManager / ColorDisplayService.
-                try {
-                    final int setting = Integer.parseInt(value);
-                    final boolean isInFrameworkRange =
-                            setting >= ColorDisplayManager.COLOR_MODE_NATURAL
-                                    && setting <= ColorDisplayManager.COLOR_MODE_AUTOMATIC;
-                    final boolean isInVendorRange =
-                            setting >= ColorDisplayManager.VENDOR_COLOR_MODE_RANGE_MIN
-                                    && setting <= ColorDisplayManager.VENDOR_COLOR_MODE_RANGE_MAX;
-                    return isInFrameworkRange || isInVendorRange;
-                } catch (NumberFormatException | NullPointerException e) {
-                    return false;
-                }
-            }
-        };
-
         /**
          * The user selected min refresh rate in frames per second.
          *
@@ -3510,9 +3397,6 @@
          */
         public static final String PEAK_REFRESH_RATE = "peak_refresh_rate";
 
-        private static final Validator PEAK_REFRESH_RATE_VALIDATOR =
-                new InclusiveFloatRangeValidator(24f, Float.MAX_VALUE);
-
         /**
          * The amount of time in milliseconds before the device goes to sleep or begins
          * to dream after a period of inactivity.  This value is also known as the
@@ -3525,9 +3409,6 @@
          */
         public static final String SCREEN_OFF_TIMEOUT = "screen_off_timeout";
 
-        private static final Validator SCREEN_OFF_TIMEOUT_VALIDATOR =
-                NON_NEGATIVE_INTEGER_VALIDATOR;
-
         /**
          * The screen backlight brightness between 0 and 255.
          */
@@ -3539,16 +3420,11 @@
          */
         public static final String SCREEN_BRIGHTNESS_FOR_VR = "screen_brightness_for_vr";
 
-        private static final Validator SCREEN_BRIGHTNESS_FOR_VR_VALIDATOR =
-                new InclusiveIntegerRangeValidator(0, 255);
-
         /**
          * Control whether to enable automatic brightness mode.
          */
         public static final String SCREEN_BRIGHTNESS_MODE = "screen_brightness_mode";
 
-        private static final Validator SCREEN_BRIGHTNESS_MODE_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Adjustment to auto-brightness to make it generally more (>0.0 <1.0)
          * or less (<0.0 >-1.0) bright.
@@ -3557,9 +3433,6 @@
         @UnsupportedAppUsage
         public static final String SCREEN_AUTO_BRIGHTNESS_ADJ = "screen_auto_brightness_adj";
 
-        private static final Validator SCREEN_AUTO_BRIGHTNESS_ADJ_VALIDATOR =
-                new InclusiveFloatRangeValidator(-1, 1);
-
         /**
          * SCREEN_BRIGHTNESS_MODE value for manual mode.
          */
@@ -3576,8 +3449,6 @@
          */
         public static final String ADAPTIVE_SLEEP = "adaptive_sleep";
 
-        private static final Validator ADAPTIVE_SLEEP_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Control whether the process CPU usage meter should be shown.
          *
@@ -3604,9 +3475,6 @@
          */
         public static final String MODE_RINGER_STREAMS_AFFECTED = "mode_ringer_streams_affected";
 
-        private static final Validator MODE_RINGER_STREAMS_AFFECTED_VALIDATOR =
-                NON_NEGATIVE_INTEGER_VALIDATOR;
-
         /**
           * Determines which streams are affected by mute. The
           * stream type's bit should be set to 1 if it should be muted when a mute request
@@ -3614,17 +3482,12 @@
           */
         public static final String MUTE_STREAMS_AFFECTED = "mute_streams_affected";
 
-        private static final Validator MUTE_STREAMS_AFFECTED_VALIDATOR =
-                NON_NEGATIVE_INTEGER_VALIDATOR;
-
         /**
          * Whether vibrate is on for different events. This is used internally,
          * changing this value will not change the vibrate. See AudioManager.
          */
         public static final String VIBRATE_ON = "vibrate_on";
 
-        private static final Validator VIBRATE_ON_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * If 1, redirects the system vibrator to all currently attached input devices
          * that support vibration.  If there are no such input devices, then the system
@@ -3639,8 +3502,6 @@
          */
         public static final String VIBRATE_INPUT_DEVICES = "vibrate_input_devices";
 
-        private static final Validator VIBRATE_INPUT_DEVICES_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * The intensity of notification vibrations, if configurable.
          *
@@ -3691,9 +3552,6 @@
         public static final String HAPTIC_FEEDBACK_INTENSITY =
                 "haptic_feedback_intensity";
 
-        private static final Validator VIBRATION_INTENSITY_VALIDATOR =
-                new InclusiveIntegerRangeValidator(0, 3);
-
         /**
          * Ringer volume. This is used internally, changing this value will not
          * change the volume. See AudioManager.
@@ -3772,8 +3630,6 @@
         @UnsupportedAppUsage
         public static final String MASTER_MONO = "master_mono";
 
-        private static final Validator MASTER_MONO_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Master balance (float -1.f = 100% left, 0.f = dead center, 1.f = 100% right).
          *
@@ -3781,9 +3637,6 @@
          */
         public static final String MASTER_BALANCE = "master_balance";
 
-        private static final Validator MASTER_BALANCE_VALIDATOR =
-                new InclusiveFloatRangeValidator(-1.f, 1.f);
-
         /**
          * Whether the notifications should use the ring volume (value of 1) or
          * a separate notification volume (value of 0). In most cases, users
@@ -3802,8 +3655,6 @@
         public static final String NOTIFICATIONS_USE_RING_VOLUME =
             "notifications_use_ring_volume";
 
-        private static final Validator NOTIFICATIONS_USE_RING_VOLUME_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Whether silent mode should allow vibration feedback. This is used
          * internally in AudioService and the Sound settings activity to
@@ -3819,8 +3670,6 @@
         @UnsupportedAppUsage
         public static final String VIBRATE_IN_SILENT = "vibrate_in_silent";
 
-        private static final Validator VIBRATE_IN_SILENT_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * The mapping of stream type (integer) to its setting.
          *
@@ -3867,8 +3716,6 @@
          */
         public static final String RINGTONE = "ringtone";
 
-        private static final Validator RINGTONE_VALIDATOR = URI_VALIDATOR;
-
         /**
          * A {@link Uri} that will point to the current default ringtone at any
          * given time.
@@ -3892,8 +3739,6 @@
          */
         public static final String NOTIFICATION_SOUND = "notification_sound";
 
-        private static final Validator NOTIFICATION_SOUND_VALIDATOR = URI_VALIDATOR;
-
         /**
          * A {@link Uri} that will point to the current default notification
          * sound at any given time.
@@ -3915,8 +3760,6 @@
          */
         public static final String ALARM_ALERT = "alarm_alert";
 
-        private static final Validator ALARM_ALERT_VALIDATOR = URI_VALIDATOR;
-
         /**
          * A {@link Uri} that will point to the current default alarm alert at
          * any given time.
@@ -3937,42 +3780,30 @@
          */
         public static final String MEDIA_BUTTON_RECEIVER = "media_button_receiver";
 
-        private static final Validator MEDIA_BUTTON_RECEIVER_VALIDATOR = COMPONENT_NAME_VALIDATOR;
-
         /**
          * Setting to enable Auto Replace (AutoText) in text editors. 1 = On, 0 = Off
          */
         public static final String TEXT_AUTO_REPLACE = "auto_replace";
 
-        private static final Validator TEXT_AUTO_REPLACE_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Setting to enable Auto Caps in text editors. 1 = On, 0 = Off
          */
         public static final String TEXT_AUTO_CAPS = "auto_caps";
 
-        private static final Validator TEXT_AUTO_CAPS_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Setting to enable Auto Punctuate in text editors. 1 = On, 0 = Off. This
          * feature converts two spaces to a "." and space.
          */
         public static final String TEXT_AUTO_PUNCTUATE = "auto_punctuate";
 
-        private static final Validator TEXT_AUTO_PUNCTUATE_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Setting to showing password characters in text editors. 1 = On, 0 = Off
          */
         public static final String TEXT_SHOW_PASSWORD = "show_password";
 
-        private static final Validator TEXT_SHOW_PASSWORD_VALIDATOR = BOOLEAN_VALIDATOR;
-
         public static final String SHOW_GTALK_SERVICE_STATUS =
                 "SHOW_GTALK_SERVICE_STATUS";
 
-        private static final Validator SHOW_GTALK_SERVICE_STATUS_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Name of activity to use for wallpaper on the home screen.
          *
@@ -3981,18 +3812,6 @@
         @Deprecated
         public static final String WALLPAPER_ACTIVITY = "wallpaper_activity";
 
-        private static final Validator WALLPAPER_ACTIVITY_VALIDATOR = new Validator() {
-            private static final int MAX_LENGTH = 1000;
-
-            @Override
-            public boolean validate(String value) {
-                if (value != null && value.length() > MAX_LENGTH) {
-                    return false;
-                }
-                return ComponentName.unflattenFromString(value) != null;
-            }
-        };
-
         /**
          * @deprecated Use {@link android.provider.Settings.Global#AUTO_TIME}
          * instead
@@ -4000,8 +3819,6 @@
         @Deprecated
         public static final String AUTO_TIME = Global.AUTO_TIME;
 
-        private static final Validator AUTO_TIME_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * @deprecated Use {@link android.provider.Settings.Global#AUTO_TIME_ZONE}
          * instead
@@ -4009,8 +3826,6 @@
         @Deprecated
         public static final String AUTO_TIME_ZONE = Global.AUTO_TIME_ZONE;
 
-        private static final Validator AUTO_TIME_ZONE_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Display times as 12 or 24 hours
          *   12
@@ -4018,10 +3833,6 @@
          */
         public static final String TIME_12_24 = "time_12_24";
 
-        /** @hide */
-        public static final Validator TIME_12_24_VALIDATOR =
-                new DiscreteValueValidator(new String[] {"12", "24", null});
-
         /**
          * Date format string
          *   mm/dd/yyyy
@@ -4030,19 +3841,6 @@
          */
         public static final String DATE_FORMAT = "date_format";
 
-        /** @hide */
-        public static final Validator DATE_FORMAT_VALIDATOR = new Validator() {
-            @Override
-            public boolean validate(@Nullable String value) {
-                try {
-                    new SimpleDateFormat(value);
-                    return true;
-                } catch (IllegalArgumentException | NullPointerException e) {
-                    return false;
-                }
-            }
-        };
-
         /**
          * Whether the setup wizard has been run before (on first boot), or if
          * it still needs to be run.
@@ -4052,9 +3850,6 @@
          */
         public static final String SETUP_WIZARD_HAS_RUN = "setup_wizard_has_run";
 
-        /** @hide */
-        public static final Validator SETUP_WIZARD_HAS_RUN_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Scaling factor for normal window animations. Setting to 0 will disable window
          * animations.
@@ -4091,9 +3886,6 @@
          */
         public static final String ACCELEROMETER_ROTATION = "accelerometer_rotation";
 
-        /** @hide */
-        public static final Validator ACCELEROMETER_ROTATION_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Default screen rotation when no other policy applies.
          * When {@link #ACCELEROMETER_ROTATION} is zero and no on-screen Activity expresses a
@@ -4104,10 +3896,6 @@
          */
         public static final String USER_ROTATION = "user_rotation";
 
-        /** @hide */
-        public static final Validator USER_ROTATION_VALIDATOR =
-                new InclusiveIntegerRangeValidator(0, 3);
-
         /**
          * Control whether the rotation lock toggle in the System UI should be hidden.
          * Typically this is done for accessibility purposes to make it harder for
@@ -4123,10 +3911,6 @@
         public static final String HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY =
                 "hide_rotation_lock_toggle_for_accessibility";
 
-        /** @hide */
-        public static final Validator HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * Whether the phone vibrates when it is ringing due to an incoming call. This will
          * be used by Phone and Setting apps; it shouldn't affect other apps.
@@ -4139,9 +3923,6 @@
          */
         public static final String VIBRATE_WHEN_RINGING = "vibrate_when_ringing";
 
-        /** @hide */
-        public static final Validator VIBRATE_WHEN_RINGING_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * When {@code 1}, Telecom enhanced call blocking functionality is enabled.  When
          * {@code 0}, enhanced call blocking functionality is disabled.
@@ -4156,9 +3937,6 @@
          */
         public static final String DTMF_TONE_WHEN_DIALING = "dtmf_tone";
 
-        /** @hide */
-        public static final Validator DTMF_TONE_WHEN_DIALING_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * CDMA only settings
          * DTMF tone type played by the dialer when dialing.
@@ -4167,9 +3945,6 @@
          */
         public static final String DTMF_TONE_TYPE_WHEN_DIALING = "dtmf_tone_type";
 
-        /** @hide */
-        public static final Validator DTMF_TONE_TYPE_WHEN_DIALING_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Whether the hearing aid is enabled. The value is
          * boolean (1 or 0).
@@ -4178,9 +3953,6 @@
         @UnsupportedAppUsage
         public static final String HEARING_AID = "hearing_aid";
 
-        /** @hide */
-        public static final Validator HEARING_AID_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * CDMA only settings
          * TTY Mode
@@ -4193,28 +3965,18 @@
         @UnsupportedAppUsage
         public static final String TTY_MODE = "tty_mode";
 
-        /** @hide */
-        public static final Validator TTY_MODE_VALIDATOR =
-                new InclusiveIntegerRangeValidator(0, 3);
-
         /**
          * Whether the sounds effects (key clicks, lid open ...) are enabled. The value is
          * boolean (1 or 0).
          */
         public static final String SOUND_EFFECTS_ENABLED = "sound_effects_enabled";
 
-        /** @hide */
-        public static final Validator SOUND_EFFECTS_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Whether haptic feedback (Vibrate on tap) is enabled. The value is
          * boolean (1 or 0).
          */
         public static final String HAPTIC_FEEDBACK_ENABLED = "haptic_feedback_enabled";
 
-        /** @hide */
-        public static final Validator HAPTIC_FEEDBACK_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * @deprecated Each application that shows web suggestions should have its own
          * setting for this.
@@ -4222,9 +3984,6 @@
         @Deprecated
         public static final String SHOW_WEB_SUGGESTIONS = "show_web_suggestions";
 
-        /** @hide */
-        public static final Validator SHOW_WEB_SUGGESTIONS_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Whether the notification LED should repeatedly flash when a notification is
          * pending. The value is boolean (1 or 0).
@@ -4233,9 +3992,6 @@
         @UnsupportedAppUsage
         public static final String NOTIFICATION_LIGHT_PULSE = "notification_light_pulse";
 
-        /** @hide */
-        public static final Validator NOTIFICATION_LIGHT_PULSE_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Show pointer location on screen?
          * 0 = no
@@ -4245,9 +4001,6 @@
         @UnsupportedAppUsage
         public static final String POINTER_LOCATION = "pointer_location";
 
-        /** @hide */
-        public static final Validator POINTER_LOCATION_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Show touch positions on screen?
          * 0 = no
@@ -4257,9 +4010,6 @@
         @UnsupportedAppUsage
         public static final String SHOW_TOUCHES = "show_touches";
 
-        /** @hide */
-        public static final Validator SHOW_TOUCHES_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Log raw orientation data from
          * {@link com.android.server.policy.WindowOrientationListener} for use with the
@@ -4271,9 +4021,6 @@
         public static final String WINDOW_ORIENTATION_LISTENER_LOG =
                 "window_orientation_listener_log";
 
-        /** @hide */
-        public static final Validator WINDOW_ORIENTATION_LISTENER_LOG_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * @deprecated Use {@link android.provider.Settings.Global#POWER_SOUNDS_ENABLED}
          * instead
@@ -4282,8 +4029,6 @@
         @Deprecated
         public static final String POWER_SOUNDS_ENABLED = Global.POWER_SOUNDS_ENABLED;
 
-        private static final Validator POWER_SOUNDS_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * @deprecated Use {@link android.provider.Settings.Global#DOCK_SOUNDS_ENABLED}
          * instead
@@ -4293,8 +4038,6 @@
         @UnsupportedAppUsage
         public static final String DOCK_SOUNDS_ENABLED = Global.DOCK_SOUNDS_ENABLED;
 
-        private static final Validator DOCK_SOUNDS_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Whether to play sounds when the keyguard is shown and dismissed.
          * @hide
@@ -4302,18 +4045,12 @@
         @UnsupportedAppUsage
         public static final String LOCKSCREEN_SOUNDS_ENABLED = "lockscreen_sounds_enabled";
 
-        /** @hide */
-        public static final Validator LOCKSCREEN_SOUNDS_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Whether the lockscreen should be completely disabled.
          * @hide
          */
         public static final String LOCKSCREEN_DISABLED = "lockscreen.disabled";
 
-        /** @hide */
-        public static final Validator LOCKSCREEN_DISABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * @deprecated Use {@link android.provider.Settings.Global#LOW_BATTERY_SOUND}
          * instead
@@ -4384,9 +4121,6 @@
          */
         public static final String SIP_RECEIVE_CALLS = "sip_receive_calls";
 
-        /** @hide */
-        public static final Validator SIP_RECEIVE_CALLS_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Call Preference String.
          * "SIP_ALWAYS" : Always use SIP with network access
@@ -4395,29 +4129,18 @@
          */
         public static final String SIP_CALL_OPTIONS = "sip_call_options";
 
-        /** @hide */
-        public static final Validator SIP_CALL_OPTIONS_VALIDATOR =
-                new DiscreteValueValidator(
-                        new String[] {"SIP_ALWAYS", "SIP_ADDRESS_ONLY"});
-
         /**
          * One of the sip call options: Always use SIP with network access.
          * @hide
          */
         public static final String SIP_ALWAYS = "SIP_ALWAYS";
 
-        /** @hide */
-        public static final Validator SIP_ALWAYS_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * One of the sip call options: Only if destination is a SIP address.
          * @hide
          */
         public static final String SIP_ADDRESS_ONLY = "SIP_ADDRESS_ONLY";
 
-        /** @hide */
-        public static final Validator SIP_ADDRESS_ONLY_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * @deprecated Use SIP_ALWAYS or SIP_ADDRESS_ONLY instead.  Formerly used to indicate that
          * the user should be prompted each time a call is made whether it should be placed using
@@ -4428,9 +4151,6 @@
         @Deprecated
         public static final String SIP_ASK_ME_EACH_TIME = "SIP_ASK_ME_EACH_TIME";
 
-        /** @hide */
-        public static final Validator SIP_ASK_ME_EACH_TIME_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Pointer speed setting.
          * This is an integer value in a range between -7 and +7, so there are 15 possible values.
@@ -4442,19 +4162,12 @@
         @UnsupportedAppUsage
         public static final String POINTER_SPEED = "pointer_speed";
 
-        /** @hide */
-        public static final Validator POINTER_SPEED_VALIDATOR =
-                new InclusiveFloatRangeValidator(-7, 7);
-
         /**
          * Whether lock-to-app will be triggered by long-press on recents.
          * @hide
          */
         public static final String LOCK_TO_APP_ENABLED = "lock_to_app_enabled";
 
-        /** @hide */
-        public static final Validator LOCK_TO_APP_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * I am the lolrus.
          * <p>
@@ -4464,18 +4177,6 @@
          */
         public static final String EGG_MODE = "egg_mode";
 
-        /** @hide */
-        public static final Validator EGG_MODE_VALIDATOR = new Validator() {
-            @Override
-            public boolean validate(@Nullable String value) {
-                try {
-                    return Long.parseLong(value) >= 0;
-                } catch (NumberFormatException e) {
-                    return false;
-                }
-            }
-        };
-
         /**
          * Setting to determine whether or not to show the battery percentage in the status bar.
          *    0 - Don't show percentage
@@ -4484,9 +4185,6 @@
          */
         public static final String SHOW_BATTERY_PERCENT = "status_bar_show_battery_percent";
 
-        /** @hide */
-        private static final Validator SHOW_BATTERY_PERCENT_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * IMPORTANT: If you add a new public settings you also have to add it to
          * PUBLIC_SETTINGS below. If the new setting is hidden you have to add
@@ -4495,73 +4193,6 @@
          */
 
         /**
-         * Settings to backup. This is here so that it's in the same place as the settings
-         * keys and easy to update.
-         *
-         * NOTE: Settings are backed up and restored in the order they appear
-         *       in this array. If you have one setting depending on another,
-         *       make sure that they are ordered appropriately.
-         *
-         * @hide
-         */
-        @UnsupportedAppUsage
-        public static final String[] SETTINGS_TO_BACKUP = {
-            STAY_ON_WHILE_PLUGGED_IN,   // moved to global
-            WIFI_USE_STATIC_IP,
-            WIFI_STATIC_IP,
-            WIFI_STATIC_GATEWAY,
-            WIFI_STATIC_NETMASK,
-            WIFI_STATIC_DNS1,
-            WIFI_STATIC_DNS2,
-            BLUETOOTH_DISCOVERABILITY,
-            BLUETOOTH_DISCOVERABILITY_TIMEOUT,
-            FONT_SCALE,
-            DIM_SCREEN,
-            SCREEN_OFF_TIMEOUT,
-            SCREEN_BRIGHTNESS_MODE,
-            SCREEN_AUTO_BRIGHTNESS_ADJ,
-            SCREEN_BRIGHTNESS_FOR_VR,
-            ADAPTIVE_SLEEP,
-            VIBRATE_INPUT_DEVICES,
-            MODE_RINGER_STREAMS_AFFECTED,
-            TEXT_AUTO_REPLACE,
-            TEXT_AUTO_CAPS,
-            TEXT_AUTO_PUNCTUATE,
-            TEXT_SHOW_PASSWORD,
-            AUTO_TIME,                  // moved to global
-            AUTO_TIME_ZONE,             // moved to global
-            TIME_12_24,
-            DATE_FORMAT,
-            DTMF_TONE_WHEN_DIALING,
-            DTMF_TONE_TYPE_WHEN_DIALING,
-            HEARING_AID,
-            TTY_MODE,
-            MASTER_MONO,
-            MASTER_BALANCE,
-            SOUND_EFFECTS_ENABLED,
-            HAPTIC_FEEDBACK_ENABLED,
-            POWER_SOUNDS_ENABLED,       // moved to global
-            DOCK_SOUNDS_ENABLED,        // moved to global
-            LOCKSCREEN_SOUNDS_ENABLED,
-            SHOW_WEB_SUGGESTIONS,
-            SIP_CALL_OPTIONS,
-            SIP_RECEIVE_CALLS,
-            POINTER_SPEED,
-            VIBRATE_WHEN_RINGING,
-            RINGTONE,
-            LOCK_TO_APP_ENABLED,
-            NOTIFICATION_SOUND,
-            ACCELEROMETER_ROTATION,
-            SHOW_BATTERY_PERCENT,
-            NOTIFICATION_VIBRATION_INTENSITY,
-            RING_VIBRATION_INTENSITY,
-            HAPTIC_FEEDBACK_INTENSITY,
-            DISPLAY_COLOR_MODE,
-            ALARM_ALERT,
-            NOTIFICATION_LIGHT_PULSE,
-        };
-
-        /**
          * Keys we no longer back up under the current schema, but want to continue to
          * process when restoring historical backup datasets.
          *
@@ -4681,99 +4312,6 @@
         }
 
         /**
-         * These are all public system settings
-         *
-         * All settings in {@link SETTINGS_TO_BACKUP} array *must* have a non-null validator,
-         * otherwise they won't be restored.
-         *
-         * @hide
-         */
-        @UnsupportedAppUsage
-        public static final Map<String, Validator> VALIDATORS = new ArrayMap<>();
-        static {
-            VALIDATORS.put(STAY_ON_WHILE_PLUGGED_IN, STAY_ON_WHILE_PLUGGED_IN_VALIDATOR);
-            VALIDATORS.put(END_BUTTON_BEHAVIOR, END_BUTTON_BEHAVIOR_VALIDATOR);
-            VALIDATORS.put(WIFI_USE_STATIC_IP, WIFI_USE_STATIC_IP_VALIDATOR);
-            VALIDATORS.put(BLUETOOTH_DISCOVERABILITY, BLUETOOTH_DISCOVERABILITY_VALIDATOR);
-            VALIDATORS.put(BLUETOOTH_DISCOVERABILITY_TIMEOUT,
-                    BLUETOOTH_DISCOVERABILITY_TIMEOUT_VALIDATOR);
-            VALIDATORS.put(NEXT_ALARM_FORMATTED, NEXT_ALARM_FORMATTED_VALIDATOR);
-            VALIDATORS.put(FONT_SCALE, FONT_SCALE_VALIDATOR);
-            VALIDATORS.put(DIM_SCREEN, DIM_SCREEN_VALIDATOR);
-            VALIDATORS.put(DISPLAY_COLOR_MODE, DISPLAY_COLOR_MODE_VALIDATOR);
-            VALIDATORS.put(SCREEN_OFF_TIMEOUT, SCREEN_OFF_TIMEOUT_VALIDATOR);
-            VALIDATORS.put(SCREEN_BRIGHTNESS_FOR_VR, SCREEN_BRIGHTNESS_FOR_VR_VALIDATOR);
-            VALIDATORS.put(SCREEN_BRIGHTNESS_MODE, SCREEN_BRIGHTNESS_MODE_VALIDATOR);
-            VALIDATORS.put(ADAPTIVE_SLEEP, ADAPTIVE_SLEEP_VALIDATOR);
-            VALIDATORS.put(MODE_RINGER_STREAMS_AFFECTED, MODE_RINGER_STREAMS_AFFECTED_VALIDATOR);
-            VALIDATORS.put(MUTE_STREAMS_AFFECTED, MUTE_STREAMS_AFFECTED_VALIDATOR);
-            VALIDATORS.put(VIBRATE_ON, VIBRATE_ON_VALIDATOR);
-            VALIDATORS.put(NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);
-            VALIDATORS.put(RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);
-            VALIDATORS.put(HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);
-            VALIDATORS.put(RINGTONE, RINGTONE_VALIDATOR);
-            VALIDATORS.put(NOTIFICATION_SOUND, NOTIFICATION_SOUND_VALIDATOR);
-            VALIDATORS.put(ALARM_ALERT, ALARM_ALERT_VALIDATOR);
-            VALIDATORS.put(TEXT_AUTO_REPLACE, TEXT_AUTO_REPLACE_VALIDATOR);
-            VALIDATORS.put(TEXT_AUTO_CAPS, TEXT_AUTO_CAPS_VALIDATOR);
-            VALIDATORS.put(TEXT_AUTO_PUNCTUATE, TEXT_AUTO_PUNCTUATE_VALIDATOR);
-            VALIDATORS.put(TEXT_SHOW_PASSWORD, TEXT_SHOW_PASSWORD_VALIDATOR);
-            VALIDATORS.put(AUTO_TIME, AUTO_TIME_VALIDATOR);
-            VALIDATORS.put(AUTO_TIME_ZONE, AUTO_TIME_ZONE_VALIDATOR);
-            VALIDATORS.put(SHOW_GTALK_SERVICE_STATUS, SHOW_GTALK_SERVICE_STATUS_VALIDATOR);
-            VALIDATORS.put(WALLPAPER_ACTIVITY, WALLPAPER_ACTIVITY_VALIDATOR);
-            VALIDATORS.put(TIME_12_24, TIME_12_24_VALIDATOR);
-            VALIDATORS.put(DATE_FORMAT, DATE_FORMAT_VALIDATOR);
-            VALIDATORS.put(SETUP_WIZARD_HAS_RUN, SETUP_WIZARD_HAS_RUN_VALIDATOR);
-            VALIDATORS.put(ACCELEROMETER_ROTATION, ACCELEROMETER_ROTATION_VALIDATOR);
-            VALIDATORS.put(USER_ROTATION, USER_ROTATION_VALIDATOR);
-            VALIDATORS.put(DTMF_TONE_WHEN_DIALING, DTMF_TONE_WHEN_DIALING_VALIDATOR);
-            VALIDATORS.put(SOUND_EFFECTS_ENABLED, SOUND_EFFECTS_ENABLED_VALIDATOR);
-            VALIDATORS.put(HAPTIC_FEEDBACK_ENABLED, HAPTIC_FEEDBACK_ENABLED_VALIDATOR);
-            VALIDATORS.put(POWER_SOUNDS_ENABLED, POWER_SOUNDS_ENABLED_VALIDATOR);
-            VALIDATORS.put(DOCK_SOUNDS_ENABLED, DOCK_SOUNDS_ENABLED_VALIDATOR);
-            VALIDATORS.put(SHOW_WEB_SUGGESTIONS, SHOW_WEB_SUGGESTIONS_VALIDATOR);
-            VALIDATORS.put(WIFI_USE_STATIC_IP, WIFI_USE_STATIC_IP_VALIDATOR);
-            VALIDATORS.put(END_BUTTON_BEHAVIOR, END_BUTTON_BEHAVIOR_VALIDATOR);
-            VALIDATORS.put(ADVANCED_SETTINGS, ADVANCED_SETTINGS_VALIDATOR);
-            VALIDATORS.put(SCREEN_AUTO_BRIGHTNESS_ADJ, SCREEN_AUTO_BRIGHTNESS_ADJ_VALIDATOR);
-            VALIDATORS.put(VIBRATE_INPUT_DEVICES, VIBRATE_INPUT_DEVICES_VALIDATOR);
-            VALIDATORS.put(MASTER_MONO, MASTER_MONO_VALIDATOR);
-            VALIDATORS.put(MASTER_BALANCE, MASTER_BALANCE_VALIDATOR);
-            VALIDATORS.put(NOTIFICATIONS_USE_RING_VOLUME, NOTIFICATIONS_USE_RING_VOLUME_VALIDATOR);
-            VALIDATORS.put(VIBRATE_IN_SILENT, VIBRATE_IN_SILENT_VALIDATOR);
-            VALIDATORS.put(MEDIA_BUTTON_RECEIVER, MEDIA_BUTTON_RECEIVER_VALIDATOR);
-            VALIDATORS.put(HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY,
-                    HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY_VALIDATOR);
-            VALIDATORS.put(VIBRATE_WHEN_RINGING, VIBRATE_WHEN_RINGING_VALIDATOR);
-            VALIDATORS.put(DTMF_TONE_TYPE_WHEN_DIALING, DTMF_TONE_TYPE_WHEN_DIALING_VALIDATOR);
-            VALIDATORS.put(HEARING_AID, HEARING_AID_VALIDATOR);
-            VALIDATORS.put(TTY_MODE, TTY_MODE_VALIDATOR);
-            VALIDATORS.put(NOTIFICATION_LIGHT_PULSE, NOTIFICATION_LIGHT_PULSE_VALIDATOR);
-            VALIDATORS.put(POINTER_LOCATION, POINTER_LOCATION_VALIDATOR);
-            VALIDATORS.put(SHOW_TOUCHES, SHOW_TOUCHES_VALIDATOR);
-            VALIDATORS.put(WINDOW_ORIENTATION_LISTENER_LOG,
-                    WINDOW_ORIENTATION_LISTENER_LOG_VALIDATOR);
-            VALIDATORS.put(LOCKSCREEN_SOUNDS_ENABLED, LOCKSCREEN_SOUNDS_ENABLED_VALIDATOR);
-            VALIDATORS.put(LOCKSCREEN_DISABLED, LOCKSCREEN_DISABLED_VALIDATOR);
-            VALIDATORS.put(SIP_RECEIVE_CALLS, SIP_RECEIVE_CALLS_VALIDATOR);
-            VALIDATORS.put(SIP_CALL_OPTIONS, SIP_CALL_OPTIONS_VALIDATOR);
-            VALIDATORS.put(SIP_ALWAYS, SIP_ALWAYS_VALIDATOR);
-            VALIDATORS.put(SIP_ADDRESS_ONLY, SIP_ADDRESS_ONLY_VALIDATOR);
-            VALIDATORS.put(SIP_ASK_ME_EACH_TIME, SIP_ASK_ME_EACH_TIME_VALIDATOR);
-            VALIDATORS.put(POINTER_SPEED, POINTER_SPEED_VALIDATOR);
-            VALIDATORS.put(LOCK_TO_APP_ENABLED, LOCK_TO_APP_ENABLED_VALIDATOR);
-            VALIDATORS.put(EGG_MODE, EGG_MODE_VALIDATOR);
-            VALIDATORS.put(WIFI_STATIC_IP, WIFI_STATIC_IP_VALIDATOR);
-            VALIDATORS.put(WIFI_STATIC_GATEWAY, WIFI_STATIC_GATEWAY_VALIDATOR);
-            VALIDATORS.put(WIFI_STATIC_NETMASK, WIFI_STATIC_NETMASK_VALIDATOR);
-            VALIDATORS.put(WIFI_STATIC_DNS1, WIFI_STATIC_DNS1_VALIDATOR);
-            VALIDATORS.put(WIFI_STATIC_DNS2, WIFI_STATIC_DNS2_VALIDATOR);
-            VALIDATORS.put(SHOW_BATTERY_PERCENT, SHOW_BATTERY_PERCENT_VALIDATOR);
-            VALIDATORS.put(NOTIFICATION_LIGHT_PULSE, BOOLEAN_VALIDATOR);
-        }
-
-        /**
          * These entries are considered common between the personal and the managed profile,
          * since the managed profile doesn't get to change them.
          */
@@ -4859,8 +4397,6 @@
         @Deprecated
         public static final String BLUETOOTH_ON = Global.BLUETOOTH_ON;
 
-        private static final Validator BLUETOOTH_ON_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * @deprecated Use {@link android.provider.Settings.Global#DATA_ROAMING} instead
          */
@@ -4938,8 +4474,6 @@
         @Deprecated
         public static final String USB_MASS_STORAGE_ENABLED = Global.USB_MASS_STORAGE_ENABLED;
 
-        private static final Validator USB_MASS_STORAGE_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * @deprecated Use {@link android.provider.Settings.Global#USE_GOOGLE_MAIL} instead
          */
@@ -4969,9 +4503,6 @@
         public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON =
                 Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON;
 
-        private static final Validator WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * @deprecated Use
          * {@link android.provider.Settings.Global#WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY} instead
@@ -4980,9 +4511,6 @@
         public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY =
                 Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY;
 
-        private static final Validator WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY_VALIDATOR =
-                NON_NEGATIVE_INTEGER_VALIDATOR;
-
         /**
          * @deprecated Use {@link android.provider.Settings.Global#WIFI_NUM_OPEN_NETWORKS_KEPT}
          * instead
@@ -4990,9 +4518,6 @@
         @Deprecated
         public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = Global.WIFI_NUM_OPEN_NETWORKS_KEPT;
 
-        private static final Validator WIFI_NUM_OPEN_NETWORKS_KEPT_VALIDATOR =
-                NON_NEGATIVE_INTEGER_VALIDATOR;
-
         /**
          * @deprecated Use {@link android.provider.Settings.Global#WIFI_ON} instead
          */
@@ -5757,8 +5282,6 @@
         @Deprecated
         public static final String BUGREPORT_IN_POWER_MENU = "bugreport_in_power_menu";
 
-        private static final Validator BUGREPORT_IN_POWER_MENU_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * @deprecated Use {@link android.provider.Settings.Global#ADB_ENABLED} instead
          */
@@ -5776,8 +5299,6 @@
         @Deprecated
         public static final String ALLOW_MOCK_LOCATION = "mock_location";
 
-        private static final Validator ALLOW_MOCK_LOCATION_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Setting to indicate that on device captions are enabled.
          *
@@ -5786,8 +5307,6 @@
         @SystemApi
         public static final String ODI_CAPTIONS_ENABLED = "odi_captions_enabled";
 
-        private static final Validator ODI_CAPTIONS_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * On Android 8.0 (API level 26) and higher versions of the platform,
          * a 64-bit number (expressed as a hexadecimal string), unique to
@@ -5833,8 +5352,6 @@
         @Deprecated
         public static final String BLUETOOTH_ON = Global.BLUETOOTH_ON;
 
-        private static final Validator BLUETOOTH_ON_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * @deprecated Use {@link android.provider.Settings.Global#DATA_ROAMING} instead
          */
@@ -5882,9 +5399,6 @@
         @TestApi
         public static final String AUTOFILL_SERVICE = "autofill_service";
 
-        private static final Validator AUTOFILL_SERVICE_VALIDATOR =
-                NULLABLE_COMPONENT_NAME_VALIDATOR;
-
         /**
          * Boolean indicating if Autofill supports field classification.
          *
@@ -6098,8 +5612,6 @@
          */
         public static final String SHOW_IME_WITH_HARD_KEYBOARD = "show_ime_with_hard_keyboard";
 
-        private static final Validator SHOW_IME_WITH_HARD_KEYBOARD_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Host name and port for global http proxy. Uses ':' seperator for
          * between host and port.
@@ -6367,9 +5879,6 @@
          */
         public static final String LOCK_SCREEN_CUSTOM_CLOCK_FACE = "lock_screen_custom_clock_face";
 
-        private static final Validator LOCK_SCREEN_CUSTOM_CLOCK_FACE_VALIDATOR =
-                JSON_OBJECT_VALIDATOR;
-
         /**
          * Indicates which clock face to show on lock screen and AOD while docked.
          * @hide
@@ -6435,8 +5944,6 @@
         @Deprecated
         public static final String USB_MASS_STORAGE_ENABLED = Global.USB_MASS_STORAGE_ENABLED;
 
-        private static final Validator USB_MASS_STORAGE_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * @deprecated Use {@link android.provider.Settings.Global#USE_GOOGLE_MAIL} instead
          */
@@ -6448,8 +5955,6 @@
          */
         public static final String ACCESSIBILITY_ENABLED = "accessibility_enabled";
 
-        private static final Validator ACCESSIBILITY_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Setting specifying if the accessibility shortcut is enabled.
          * @hide
@@ -6457,8 +5962,6 @@
         public static final String ACCESSIBILITY_SHORTCUT_ENABLED =
                 "accessibility_shortcut_enabled";
 
-        private static final Validator ACCESSIBILITY_SHORTCUT_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Setting specifying if the accessibility shortcut is enabled.
          * @hide
@@ -6466,9 +5969,6 @@
         public static final String ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN =
                 "accessibility_shortcut_on_lock_screen";
 
-        private static final Validator ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * Setting specifying if the accessibility shortcut dialog has been shown to this user.
          * @hide
@@ -6476,9 +5976,6 @@
         public static final String ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN =
                 "accessibility_shortcut_dialog_shown";
 
-        private static final Validator ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * Setting specifying the accessibility service to be toggled via the accessibility
          * shortcut. Must be its flattened {@link ComponentName}.
@@ -6488,9 +5985,6 @@
         public static final String ACCESSIBILITY_SHORTCUT_TARGET_SERVICE =
                 "accessibility_shortcut_target_service";
 
-        private static final Validator ACCESSIBILITY_SHORTCUT_TARGET_SERVICE_VALIDATOR =
-                NULLABLE_COMPONENT_NAME_VALIDATOR;
-
         /**
          * Setting specifying the accessibility service or feature to be toggled via the
          * accessibility button in the navigation bar. This is either a flattened
@@ -6501,32 +5995,17 @@
         public static final String ACCESSIBILITY_BUTTON_TARGET_COMPONENT =
                 "accessibility_button_target_component";
 
-        private static final Validator ACCESSIBILITY_BUTTON_TARGET_COMPONENT_VALIDATOR =
-                new Validator() {
-                    @Override
-                    public boolean validate(@Nullable String value) {
-                        // technically either ComponentName or class name, but there's proper value
-                        // validation at callsites, so allow any non-null string
-                        return value != null;
-                    }
-                };
-
         /**
          * If touch exploration is enabled.
          */
         public static final String TOUCH_EXPLORATION_ENABLED = "touch_exploration_enabled";
 
-        private static final Validator TOUCH_EXPLORATION_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * List of the enabled accessibility providers.
          */
         public static final String ENABLED_ACCESSIBILITY_SERVICES =
             "enabled_accessibility_services";
 
-        private static final Validator ENABLED_ACCESSIBILITY_SERVICES_VALIDATOR =
-                new ComponentNameListValidator(":");
-
         /**
          * List of the accessibility services to which the user has granted
          * permission to put the device into touch exploration mode.
@@ -6536,17 +6015,12 @@
         public static final String TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES =
             "touch_exploration_granted_accessibility_services";
 
-        private static final Validator TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES_VALIDATOR =
-                new ComponentNameListValidator(":");
-
         /**
          * Whether the Global Actions Panel is enabled.
          * @hide
          */
         public static final String GLOBAL_ACTIONS_PANEL_ENABLED = "global_actions_panel_enabled";
 
-        private static final Validator GLOBAL_ACTIONS_PANEL_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Whether the Global Actions Panel can be toggled on or off in Settings.
          * @hide
@@ -6568,17 +6042,12 @@
         @SystemApi
         public static final String HUSH_GESTURE_USED = "hush_gesture_used";
 
-        private static final Validator HUSH_GESTURE_USED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Number of times the user has manually clicked the ringer toggle
          * @hide
          */
         public static final String MANUAL_RINGER_TOGGLE_COUNT = "manual_ringer_toggle_count";
 
-        private static final Validator MANUAL_RINGER_TOGGLE_COUNT_VALIDATOR =
-                NON_NEGATIVE_INTEGER_VALIDATOR;
-
         /**
          * Whether to play a sound for charging events.
          * @hide
@@ -6600,8 +6069,6 @@
          */
         public static final String ZEN_DURATION = "zen_duration";
 
-        private static final Validator ZEN_DURATION_VALIDATOR = ANY_INTEGER_VALIDATOR;
-
         /** @hide */ public static final int ZEN_DURATION_PROMPT = -1;
         /** @hide */ public static final int ZEN_DURATION_FOREVER = 0;
 
@@ -6637,8 +6104,6 @@
          */
         public static final String IN_CALL_NOTIFICATION_ENABLED = "in_call_notification_enabled";
 
-        private static final Validator IN_CALL_NOTIFICATION_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Uri of the slice that's presented on the keyguard.
          * Defaults to a slice with the date and next alarm.
@@ -6665,9 +6130,6 @@
         public static final String ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED =
                 "high_text_contrast_enabled";
 
-        private static final Validator ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * Setting that specifies whether the display magnification is enabled via a system-wide
          * triple tap gesture. Display magnifications allows the user to zoom in the display content
@@ -6680,9 +6142,6 @@
         public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED =
                 "accessibility_display_magnification_enabled";
 
-        private static final Validator ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * Setting that specifies whether the display magnification is enabled via a shortcut
          * affordance within the system's navigation area. Display magnifications allows the user to
@@ -6695,9 +6154,6 @@
         public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED =
                 "accessibility_display_magnification_navbar_enabled";
 
-        private static final Validator ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED_VALIDATOR
-                = BOOLEAN_VALIDATOR;
-
         /**
          * Setting that specifies what the display magnification scale is.
          * Display magnifications allows the user to zoom in the display
@@ -6711,9 +6167,6 @@
         public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE =
                 "accessibility_display_magnification_scale";
 
-        private static final Validator ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE_VALIDATOR =
-                new InclusiveFloatRangeValidator(1.0f, Float.MAX_VALUE);
-
         /**
          * Unused mangnification setting
          *
@@ -6766,9 +6219,6 @@
         public static final String ACCESSIBILITY_CAPTIONING_ENABLED =
                 "accessibility_captioning_enabled";
 
-        private static final Validator ACCESSIBILITY_CAPTIONING_ENABLED_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * Setting that specifies the language for captions as a locale string,
          * e.g. en_US.
@@ -6779,8 +6229,6 @@
         public static final String ACCESSIBILITY_CAPTIONING_LOCALE =
                 "accessibility_captioning_locale";
 
-        private static final Validator ACCESSIBILITY_CAPTIONING_LOCALE_VALIDATOR = LOCALE_VALIDATOR;
-
         /**
          * Integer property that specifies the preset style for captions, one
          * of:
@@ -6795,10 +6243,6 @@
         public static final String ACCESSIBILITY_CAPTIONING_PRESET =
                 "accessibility_captioning_preset";
 
-        private static final Validator ACCESSIBILITY_CAPTIONING_PRESET_VALIDATOR =
-                new DiscreteValueValidator(new String[]{"-1", "0", "1", "2",
-                        "3", "4"});
-
         /**
          * Integer property that specifes the background color for captions as a
          * packed 32-bit color.
@@ -6809,9 +6253,6 @@
         public static final String ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR =
                 "accessibility_captioning_background_color";
 
-        private static final Validator ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR_VALIDATOR =
-                ANY_INTEGER_VALIDATOR;
-
         /**
          * Integer property that specifes the foreground color for captions as a
          * packed 32-bit color.
@@ -6822,9 +6263,6 @@
         public static final String ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR =
                 "accessibility_captioning_foreground_color";
 
-        private static final Validator ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR_VALIDATOR =
-                ANY_INTEGER_VALIDATOR;
-
         /**
          * Integer property that specifes the edge type for captions, one of:
          * <ul>
@@ -6839,9 +6277,6 @@
         public static final String ACCESSIBILITY_CAPTIONING_EDGE_TYPE =
                 "accessibility_captioning_edge_type";
 
-        private static final Validator ACCESSIBILITY_CAPTIONING_EDGE_TYPE_VALIDATOR =
-                new DiscreteValueValidator(new String[]{"0", "1", "2"});
-
         /**
          * Integer property that specifes the edge color for captions as a
          * packed 32-bit color.
@@ -6853,9 +6288,6 @@
         public static final String ACCESSIBILITY_CAPTIONING_EDGE_COLOR =
                 "accessibility_captioning_edge_color";
 
-        private static final Validator ACCESSIBILITY_CAPTIONING_EDGE_COLOR_VALIDATOR =
-                ANY_INTEGER_VALIDATOR;
-
         /**
          * Integer property that specifes the window color for captions as a
          * packed 32-bit color.
@@ -6866,9 +6298,6 @@
         public static final String ACCESSIBILITY_CAPTIONING_WINDOW_COLOR =
                 "accessibility_captioning_window_color";
 
-        private static final Validator ACCESSIBILITY_CAPTIONING_WINDOW_COLOR_VALIDATOR =
-                ANY_INTEGER_VALIDATOR;
-
         /**
          * String property that specifies the typeface for captions, one of:
          * <ul>
@@ -6885,10 +6314,6 @@
         public static final String ACCESSIBILITY_CAPTIONING_TYPEFACE =
                 "accessibility_captioning_typeface";
 
-        private static final Validator ACCESSIBILITY_CAPTIONING_TYPEFACE_VALIDATOR =
-                new DiscreteValueValidator(new String[]{"DEFAULT",
-                        "MONOSPACE", "SANS_SERIF", "SERIF"});
-
         /**
          * Floating point property that specifies font scaling for captions.
          *
@@ -6897,18 +6322,12 @@
         public static final String ACCESSIBILITY_CAPTIONING_FONT_SCALE =
                 "accessibility_captioning_font_scale";
 
-        private static final Validator ACCESSIBILITY_CAPTIONING_FONT_SCALE_VALIDATOR =
-                new InclusiveFloatRangeValidator(0.5f, 2.0f);
-
         /**
          * Setting that specifies whether display color inversion is enabled.
          */
         public static final String ACCESSIBILITY_DISPLAY_INVERSION_ENABLED =
                 "accessibility_display_inversion_enabled";
 
-        private static final Validator ACCESSIBILITY_DISPLAY_INVERSION_ENABLED_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * Setting that specifies whether display color space adjustment is
          * enabled.
@@ -6919,9 +6338,6 @@
         public static final String ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED =
                 "accessibility_display_daltonizer_enabled";
 
-        private static final Validator ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * Integer property that specifies the type of color space adjustment to
          * perform. Valid values are defined in AccessibilityManager and Settings arrays.xml:
@@ -6938,10 +6354,6 @@
         public static final String ACCESSIBILITY_DISPLAY_DALTONIZER =
                 "accessibility_display_daltonizer";
 
-        private static final Validator ACCESSIBILITY_DISPLAY_DALTONIZER_VALIDATOR =
-                new DiscreteValueValidator(
-                        new String[] {"-1", "0", "11", "12", "13"});
-
         /**
          * Setting that specifies whether automatic click when the mouse pointer stops moving is
          * enabled.
@@ -6952,9 +6364,6 @@
         public static final String ACCESSIBILITY_AUTOCLICK_ENABLED =
                 "accessibility_autoclick_enabled";
 
-        private static final Validator ACCESSIBILITY_AUTOCLICK_ENABLED_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * Integer setting specifying amount of time in ms the mouse pointer has to stay still
          * before performing click when {@link #ACCESSIBILITY_AUTOCLICK_ENABLED} is set.
@@ -6965,9 +6374,6 @@
         public static final String ACCESSIBILITY_AUTOCLICK_DELAY =
                 "accessibility_autoclick_delay";
 
-        private static final Validator ACCESSIBILITY_AUTOCLICK_DELAY_VALIDATOR =
-                NON_NEGATIVE_INTEGER_VALIDATOR;
-
         /**
          * Whether or not larger size icons are used for the pointer of mouse/trackpad for
          * accessibility.
@@ -6978,9 +6384,6 @@
         public static final String ACCESSIBILITY_LARGE_POINTER_ICON =
                 "accessibility_large_pointer_icon";
 
-        private static final Validator ACCESSIBILITY_LARGE_POINTER_ICON_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * The timeout for considering a press to be a long press in milliseconds.
          * @hide
@@ -6988,9 +6391,6 @@
         @UnsupportedAppUsage
         public static final String LONG_PRESS_TIMEOUT = "long_press_timeout";
 
-        private static final Validator LONG_PRESS_TIMEOUT_VALIDATOR =
-                NON_NEGATIVE_INTEGER_VALIDATOR;
-
         /**
          * The duration in milliseconds between the first tap's up event and the second tap's
          * down event for an interaction to be considered part of the same multi-press.
@@ -7046,8 +6446,6 @@
          */
         public static final String DISPLAY_DENSITY_FORCED = "display_density_forced";
 
-        static final Validator DISPLAY_DENSITY_FORCED_VALIDATOR = NON_NEGATIVE_INTEGER_VALIDATOR;
-
         /**
          * Setting to always use the default text-to-speech settings regardless
          * of the application settings.
@@ -7065,22 +6463,16 @@
          */
         public static final String TTS_DEFAULT_RATE = "tts_default_rate";
 
-        private static final Validator TTS_DEFAULT_RATE_VALIDATOR = NON_NEGATIVE_INTEGER_VALIDATOR;
-
         /**
          * Default text-to-speech engine pitch. 100 = 1x
          */
         public static final String TTS_DEFAULT_PITCH = "tts_default_pitch";
 
-        private static final Validator TTS_DEFAULT_PITCH_VALIDATOR = NON_NEGATIVE_INTEGER_VALIDATOR;
-
         /**
          * Default text-to-speech engine.
          */
         public static final String TTS_DEFAULT_SYNTH = "tts_default_synth";
 
-        private static final Validator TTS_DEFAULT_SYNTH_VALIDATOR = PACKAGE_NAME_VALIDATOR;
-
         /**
          * Default text-to-speech language.
          *
@@ -7128,16 +6520,11 @@
          */
         public static final String TTS_DEFAULT_LOCALE = "tts_default_locale";
 
-        private static final Validator TTS_DEFAULT_LOCALE_VALIDATOR = TTS_LIST_VALIDATOR;
-
         /**
          * Space delimited list of plugin packages that are enabled.
          */
         public static final String TTS_ENABLED_PLUGINS = "tts_enabled_plugins";
 
-        private static final Validator TTS_ENABLED_PLUGINS_VALIDATOR =
-                new PackageNameListValidator(" ");
-
         /**
          * @deprecated Use {@link android.provider.Settings.Global#WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON}
          * instead.
@@ -7146,9 +6533,6 @@
         public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON =
                 Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON;
 
-        private static final Validator WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * @deprecated Use {@link android.provider.Settings.Global#WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY}
          * instead.
@@ -7157,9 +6541,6 @@
         public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY =
                 Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY;
 
-        private static final Validator WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY_VALIDATOR =
-                NON_NEGATIVE_INTEGER_VALIDATOR;
-
         /**
          * @deprecated Use {@link android.provider.Settings.Global#WIFI_NUM_OPEN_NETWORKS_KEPT}
          * instead.
@@ -7168,9 +6549,6 @@
         public static final String WIFI_NUM_OPEN_NETWORKS_KEPT =
                 Global.WIFI_NUM_OPEN_NETWORKS_KEPT;
 
-        private static final Validator WIFI_NUM_OPEN_NETWORKS_KEPT_VALIDATOR =
-                NON_NEGATIVE_INTEGER_VALIDATOR;
-
         /**
          * @deprecated Use {@link android.provider.Settings.Global#WIFI_ON}
          * instead.
@@ -7329,9 +6707,6 @@
         public static final String PREFERRED_TTY_MODE =
                 "preferred_tty_mode";
 
-        private static final Validator PREFERRED_TTY_MODE_VALIDATOR =
-                new DiscreteValueValidator(new String[]{"0", "1", "2", "3"});
-
         /**
          * Whether the enhanced voice privacy mode is enabled.
          * 0 = normal voice privacy
@@ -7340,8 +6715,6 @@
          */
         public static final String ENHANCED_VOICE_PRIVACY_ENABLED = "enhanced_voice_privacy_enabled";
 
-        private static final Validator ENHANCED_VOICE_PRIVACY_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Whether the TTY mode mode is enabled.
          * 0 = disabled
@@ -7350,8 +6723,6 @@
          */
         public static final String TTY_MODE_ENABLED = "tty_mode_enabled";
 
-        private static final Validator TTY_MODE_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * User-selected RTT mode. When on, outgoing and incoming calls will be answered as RTT
          * calls when supported by the device and carrier. Boolean value.
@@ -7360,8 +6731,6 @@
          */
         public static final String RTT_CALLING_MODE = "rtt_calling_mode";
 
-        private static final Validator RTT_CALLING_MODE_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
         /**
          * Controls whether settings backup is enabled.
@@ -7539,32 +6908,24 @@
          */
         public static final String MOUNT_PLAY_NOTIFICATION_SND = "mount_play_not_snd";
 
-        private static final Validator MOUNT_PLAY_NOTIFICATION_SND_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Whether or not UMS auto-starts on UMS host detection. (0 = false, 1 = true)
          * @hide
          */
         public static final String MOUNT_UMS_AUTOSTART = "mount_ums_autostart";
 
-        private static final Validator MOUNT_UMS_AUTOSTART_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Whether or not a notification is displayed on UMS host detection. (0 = false, 1 = true)
          * @hide
          */
         public static final String MOUNT_UMS_PROMPT = "mount_ums_prompt";
 
-        private static final Validator MOUNT_UMS_PROMPT_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Whether or not a notification is displayed while UMS is enabled. (0 = false, 1 = true)
          * @hide
          */
         public static final String MOUNT_UMS_NOTIFY_ENABLED = "mount_ums_notify_enabled";
 
-        private static final Validator MOUNT_UMS_NOTIFY_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * If nonzero, ANRs in invisible background processes bring up a dialog.
          * Otherwise, the process will be silently killed.
@@ -7583,9 +6944,6 @@
         public static final String SHOW_FIRST_CRASH_DIALOG_DEV_OPTION =
                 "show_first_crash_dialog_dev_option";
 
-        private static final Validator SHOW_FIRST_CRASH_DIALOG_DEV_OPTION_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * The {@link ComponentName} string of the service to be used as the voice recognition
          * service.
@@ -7644,9 +7002,6 @@
         @UnsupportedAppUsage
         public static final String INCALL_POWER_BUTTON_BEHAVIOR = "incall_power_button_behavior";
 
-        private static final Validator INCALL_POWER_BUTTON_BEHAVIOR_VALIDATOR =
-                new DiscreteValueValidator(new String[]{"1", "2"});
-
         /**
          * INCALL_POWER_BUTTON_BEHAVIOR value for "turn off screen".
          * @hide
@@ -7702,8 +7057,6 @@
          */
         public static final String WAKE_GESTURE_ENABLED = "wake_gesture_enabled";
 
-        private static final Validator WAKE_GESTURE_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Whether the device should doze if configured.
          * @hide
@@ -7711,8 +7064,6 @@
         @UnsupportedAppUsage
         public static final String DOZE_ENABLED = "doze_enabled";
 
-        private static final Validator DOZE_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Indicates whether doze should be always on.
          * <p>
@@ -7724,16 +7075,12 @@
         @TestApi
         public static final String DOZE_ALWAYS_ON = "doze_always_on";
 
-        private static final Validator DOZE_ALWAYS_ON_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Whether the device should pulse on pick up gesture.
          * @hide
          */
         public static final String DOZE_PICK_UP_GESTURE = "doze_pulse_on_pick_up";
 
-        private static final Validator DOZE_PICK_UP_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Whether the device should pulse on long press gesture.
          * @hide
@@ -7746,24 +7093,18 @@
          */
         public static final String DOZE_DOUBLE_TAP_GESTURE = "doze_pulse_on_double_tap";
 
-        private static final Validator DOZE_DOUBLE_TAP_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Whether the device should respond to the SLPI tap gesture.
          * @hide
          */
         public static final String DOZE_TAP_SCREEN_GESTURE = "doze_tap_gesture";
 
-        private static final Validator DOZE_TAP_SCREEN_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Gesture that wakes up the display, showing some version of the lock screen.
          * @hide
          */
         public static final String DOZE_WAKE_LOCK_SCREEN_GESTURE = "doze_wake_screen_gesture";
 
-        private static final Validator DOZE_WAKE_LOCK_SCREEN_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Gesture that wakes up the display, toggling between {@link Display.STATE_OFF} and
          * {@link Display.STATE_DOZE}.
@@ -7771,16 +7112,12 @@
          */
         public static final String DOZE_WAKE_DISPLAY_GESTURE = "doze_wake_display_gesture";
 
-        private static final Validator DOZE_WAKE_DISPLAY_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Gesture that skips media.
          * @hide
          */
         public static final String SKIP_GESTURE = "skip_gesture";
 
-        private static final Validator SKIP_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Count of successful gestures.
          * @hide
@@ -7793,9 +7130,6 @@
          */
         public static final String SKIP_TOUCH_COUNT = "skip_touch_count";
 
-        private static final Validator SKIP_GESTURE_COUNT_VALIDATOR =
-                NON_NEGATIVE_INTEGER_VALIDATOR;
-
         /**
          * Direction to advance media for skip gesture
          * @hide
@@ -7803,21 +7137,11 @@
         public static final String SKIP_DIRECTION = "skip_gesture_direction";
 
         /**
-         * Only used if FeatureFlag "settings_skip_direction_mutable" is enabled.
-         * If feature flag is disabled, should assume SKIP_DIRECTION = 0.
-         *      0 / false = right to left to advance to next
-         *      1 / true = left to right to advance to next
-         */
-        private static final Validator SKIP_DIRECTION_VALIDATOR = BOOLEAN_VALIDATOR;
-
-        /**
          * Gesture that silences sound (alarms, notification, calls).
          * @hide
          */
         public static final String SILENCE_GESTURE = "silence_gesture";
 
-        private static final Validator SILENCE_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Count of successful silence alarms gestures.
          * @hide
@@ -7854,9 +7178,6 @@
          */
         public static final String SILENCE_CALL_TOUCH_COUNT = "silence_call_touch_count";
 
-        private static final Validator SILENCE_GESTURE_COUNT_VALIDATOR =
-                NON_NEGATIVE_INTEGER_VALIDATOR;
-
         /**
          * The current night mode that has been selected by the user.  Owned
          * and controlled by UiModeManagerService.  Constants are as per
@@ -7865,17 +7186,12 @@
          */
         public static final String UI_NIGHT_MODE = "ui_night_mode";
 
-        private static final Validator UI_NIGHT_MODE_VALIDATOR =
-                new InclusiveIntegerRangeValidator(0, 2);
-
         /**
          * Whether screensavers are enabled.
          * @hide
          */
         public static final String SCREENSAVER_ENABLED = "screensaver_enabled";
 
-        private static final Validator SCREENSAVER_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * The user's chosen screensaver components.
          *
@@ -7885,9 +7201,6 @@
          */
         public static final String SCREENSAVER_COMPONENTS = "screensaver_components";
 
-        private static final Validator SCREENSAVER_COMPONENTS_VALIDATOR =
-                new ComponentNameListValidator(",");
-
         /**
          * If screensavers are enabled, whether the screensaver should be automatically launched
          * when the device is inserted into a (desk) dock.
@@ -7895,8 +7208,6 @@
          */
         public static final String SCREENSAVER_ACTIVATE_ON_DOCK = "screensaver_activate_on_dock";
 
-        private static final Validator SCREENSAVER_ACTIVATE_ON_DOCK_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * If screensavers are enabled, whether the screensaver should be automatically launched
          * when the screen times out when not on battery.
@@ -7904,8 +7215,6 @@
          */
         public static final String SCREENSAVER_ACTIVATE_ON_SLEEP = "screensaver_activate_on_sleep";
 
-        private static final Validator SCREENSAVER_ACTIVATE_ON_SLEEP_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * If screensavers are enabled, the default screensaver component.
          * @hide
@@ -7919,9 +7228,6 @@
         @UnsupportedAppUsage
         public static final String NFC_PAYMENT_DEFAULT_COMPONENT = "nfc_payment_default_component";
 
-        private static final Validator NFC_PAYMENT_DEFAULT_COMPONENT_VALIDATOR =
-                COMPONENT_NAME_VALIDATOR;
-
         /**
          * Whether NFC payment is handled by the foreground application or a default.
          * @hide
@@ -8037,9 +7343,6 @@
         public static final String ENABLED_NOTIFICATION_ASSISTANT =
                 "enabled_notification_assistant";
 
-        private static final Validator ENABLED_NOTIFICATION_ASSISTANT_VALIDATOR =
-                new ComponentNameListValidator(":");
-
         /**
          * Read only list of the service components that the current user has explicitly allowed to
          * see all of the user's notifications, separated by ':'.
@@ -8052,9 +7355,6 @@
         @UnsupportedAppUsage
         public static final String ENABLED_NOTIFICATION_LISTENERS = "enabled_notification_listeners";
 
-        private static final Validator ENABLED_NOTIFICATION_LISTENERS_VALIDATOR =
-                new ComponentNameListValidator(":");
-
         /**
          * Read only list of the packages that the current user has explicitly allowed to
          * manage do not disturb, separated by ':'.
@@ -8067,9 +7367,6 @@
         public static final String ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES =
                 "enabled_notification_policy_access_packages";
 
-        private static final Validator ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES_VALIDATOR =
-                new PackageNameListValidator(":");
-
         /**
          * Defines whether managed profile ringtones should be synced from it's parent profile
          * <p>
@@ -8083,8 +7380,6 @@
         @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
         public static final String SYNC_PARENT_SOUNDS = "sync_parent_sounds";
 
-        private static final Validator SYNC_PARENT_SOUNDS_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /** @hide */
         @UnsupportedAppUsage
         public static final String IMMERSIVE_MODE_CONFIRMATIONS = "immersive_mode_confirmations";
@@ -8218,8 +7513,6 @@
          */
         public static final String DOUBLE_TAP_TO_WAKE = "double_tap_to_wake";
 
-        private static final Validator DOUBLE_TAP_TO_WAKE_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * The current assistant component. It could be a voice interaction service,
          * or an activity that handles ACTION_ASSIST, or empty which means using the default
@@ -8240,8 +7533,6 @@
          */
         public static final String CAMERA_GESTURE_DISABLED = "camera_gesture_disabled";
 
-        private static final Validator CAMERA_GESTURE_DISABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Whether the camera launch gesture to double tap the power button when the screen is off
          * should be disabled.
@@ -8251,9 +7542,6 @@
         public static final String CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED =
                 "camera_double_tap_power_gesture_disabled";
 
-        private static final Validator CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * Whether the camera double twist gesture to flip between front and back mode should be
          * enabled.
@@ -8263,9 +7551,6 @@
         public static final String CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED =
                 "camera_double_twist_to_flip_enabled";
 
-        private static final Validator CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * Whether or not the smart camera lift trigger that launches the camera when the user moves
          * the phone into a position for taking photos should be enabled.
@@ -8302,9 +7587,6 @@
          */
         public static final String FACE_UNLOCK_KEYGUARD_ENABLED = "face_unlock_keyguard_enabled";
 
-        private static final Validator FACE_UNLOCK_KEYGUARD_ENABLED_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * Whether or not face unlock dismisses the keyguard.
          * @hide
@@ -8312,9 +7594,6 @@
         public static final String FACE_UNLOCK_DISMISSES_KEYGUARD =
                 "face_unlock_dismisses_keyguard";
 
-        private static final Validator FACE_UNLOCK_DISMISSES_KEYGUARD_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * Whether or not media is shown automatically when bypassing as a heads up.
          * @hide
@@ -8322,9 +7601,6 @@
         public static final String SHOW_MEDIA_WHEN_BYPASSING =
                 "show_media_when_bypassing";
 
-        private static final Validator SHOW_MEDIA_WHEN_BYPASSING_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * Whether or not face unlock requires attention. This is a cached value, the source of
          * truth is obtained through the HAL.
@@ -8348,9 +7624,6 @@
          */
         public static final String FACE_UNLOCK_APP_ENABLED = "face_unlock_app_enabled";
 
-        private static final Validator FACE_UNLOCK_APP_ENABLED_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * Whether or not face unlock always requires user confirmation, meaning {@link
          * android.hardware.biometrics.BiometricPrompt.Builder#setConfirmationRequired(boolean)}
@@ -8361,9 +7634,6 @@
         public static final String FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION =
                 "face_unlock_always_require_confirmation";
 
-        private static final Validator FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * Whether or not debugging is enabled.
          * @hide
@@ -8378,9 +7648,6 @@
          */
         public static final String ASSIST_GESTURE_ENABLED = "assist_gesture_enabled";
 
-        private static final Validator ASSIST_GESTURE_ENABLED_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * Sensitivity control for the assist gesture.
          *
@@ -8396,9 +7663,6 @@
         public static final String ASSIST_GESTURE_SILENCE_ALERTS_ENABLED =
                 "assist_gesture_silence_alerts_enabled";
 
-        private static final Validator ASSIST_GESTURE_SILENCE_ALERTS_ENABLED_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * Whether the assist gesture should wake the phone.
          *
@@ -8407,9 +7671,6 @@
         public static final String ASSIST_GESTURE_WAKE_ENABLED =
                 "assist_gesture_wake_enabled";
 
-        private static final Validator ASSIST_GESTURE_WAKE_ENABLED_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * Indicates whether the Assist Gesture Deferred Setup has been completed.
          * <p>
@@ -8426,18 +7687,12 @@
          */
         public static final String TRUST_AGENTS_EXTEND_UNLOCK = "trust_agents_extend_unlock";
 
-        private static final Validator TRUST_AGENTS_EXTEND_UNLOCK_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * Control whether the screen locks when trust is lost.
          * @hide
          */
         public static final String LOCK_SCREEN_WHEN_TRUST_LOST = "lock_screen_when_trust_lost";
 
-        private static final Validator LOCK_SCREEN_WHEN_TRUST_LOST_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * Control whether Night display is currently activated.
          * @hide
@@ -8450,9 +7705,6 @@
          */
         public static final String NIGHT_DISPLAY_AUTO_MODE = "night_display_auto_mode";
 
-        private static final Validator NIGHT_DISPLAY_AUTO_MODE_VALIDATOR =
-                new InclusiveIntegerRangeValidator(0, 2);
-
         /**
          * Control the color temperature of Night Display, represented in Kelvin.
          * @hide
@@ -8460,9 +7712,6 @@
         public static final String NIGHT_DISPLAY_COLOR_TEMPERATURE =
                 "night_display_color_temperature";
 
-        private static final Validator NIGHT_DISPLAY_COLOR_TEMPERATURE_VALIDATOR =
-                NON_NEGATIVE_INTEGER_VALIDATOR;
-
         /**
          * Custom time when Night display is scheduled to activate.
          * Represented as milliseconds from midnight (e.g. 79200000 == 10pm).
@@ -8471,9 +7720,6 @@
         public static final String NIGHT_DISPLAY_CUSTOM_START_TIME =
                 "night_display_custom_start_time";
 
-        private static final Validator NIGHT_DISPLAY_CUSTOM_START_TIME_VALIDATOR =
-                NON_NEGATIVE_INTEGER_VALIDATOR;
-
         /**
          * Custom time when Night display is scheduled to deactivate.
          * Represented as milliseconds from midnight (e.g. 21600000 == 6am).
@@ -8481,9 +7727,6 @@
          */
         public static final String NIGHT_DISPLAY_CUSTOM_END_TIME = "night_display_custom_end_time";
 
-        private static final Validator NIGHT_DISPLAY_CUSTOM_END_TIME_VALIDATOR =
-                NON_NEGATIVE_INTEGER_VALIDATOR;
-
         /**
          * A String representing the LocalDateTime when Night display was last activated. Use to
          * decide whether to apply the current activated state after a reboot or user change. In
@@ -8499,9 +7742,6 @@
          */
         public static final String DISPLAY_WHITE_BALANCE_ENABLED = "display_white_balance_enabled";
 
-        private static final Validator DISPLAY_WHITE_BALANCE_ENABLED_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * Names of the service components that the current user has explicitly allowed to
          * be a VR mode listener, separated by ':'.
@@ -8511,9 +7751,6 @@
         @TestApi
         public static final String ENABLED_VR_LISTENERS = "enabled_vr_listeners";
 
-        private static final Validator ENABLED_VR_LISTENERS_VALIDATOR =
-                new ComponentNameListValidator(":");
-
         /**
          * Behavior of the display while in VR mode.
          *
@@ -8523,9 +7760,6 @@
          */
         public static final String VR_DISPLAY_MODE = "vr_display_mode";
 
-        private static final Validator VR_DISPLAY_MODE_VALIDATOR =
-                new DiscreteValueValidator(new String[]{"0", "1"});
-
         /**
          * Lower the display persistence while the system is in VR mode.
          *
@@ -8590,9 +7824,6 @@
         public static final String AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN =
                 "automatic_storage_manager_days_to_retain";
 
-        private static final Validator AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN_VALIDATOR =
-                NON_NEGATIVE_INTEGER_VALIDATOR;
-
         /**
          * Default number of days of information for the automatic storage manager to retain.
          *
@@ -8608,7 +7839,6 @@
         public static final String AUTOMATIC_STORAGE_MANAGER_BYTES_CLEARED =
                 "automatic_storage_manager_bytes_cleared";
 
-
         /**
          * Last run time for the automatic storage manager.
          *
@@ -8616,7 +7846,6 @@
          */
         public static final String AUTOMATIC_STORAGE_MANAGER_LAST_RUN =
                 "automatic_storage_manager_last_run";
-
         /**
          * If the automatic storage manager has been disabled by policy. Note that this doesn't
          * mean that the automatic storage manager is prevented from being re-enabled -- this only
@@ -8634,8 +7863,6 @@
         public static final String SYSTEM_NAVIGATION_KEYS_ENABLED =
                 "system_navigation_keys_enabled";
 
-        private static final Validator SYSTEM_NAVIGATION_KEYS_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Holds comma separated list of ordering of QS tiles.
          *
@@ -8643,8 +7870,6 @@
          */
         public static final String QS_TILES = "sysui_qs_tiles";
 
-        private static final Validator QS_TILES_VALIDATOR = TILE_LIST_VALIDATOR;
-
         /**
          * Specifies whether the web action API is enabled.
          *
@@ -8681,8 +7906,6 @@
         @TestApi
         public static final String NOTIFICATION_BADGING = "notification_badging";
 
-        private static final Validator NOTIFICATION_BADGING_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Whether the notification bubbles are globally enabled
          * The value is boolean (1 or 0).
@@ -8691,8 +7914,6 @@
         @TestApi
         public static final String NOTIFICATION_BUBBLES = "notification_bubbles";
 
-        private static final Validator NOTIFICATION_BUBBLES_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Whether notifications are dismissed by a right-to-left swipe (instead of a left-to-right
          * swipe).
@@ -8701,24 +7922,18 @@
          */
         public static final String NOTIFICATION_DISMISS_RTL = "notification_dismiss_rtl";
 
-        private static final Validator NOTIFICATION_DISMISS_RTL_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Comma separated list of QS tiles that have been auto-added already.
          * @hide
          */
         public static final String QS_AUTO_ADDED_TILES = "qs_auto_tiles";
 
-        private static final Validator QS_AUTO_ADDED_TILES_VALIDATOR = TILE_LIST_VALIDATOR;
-
         /**
          * Whether the Lockdown button should be shown in the power menu.
          * @hide
          */
         public static final String LOCKDOWN_IN_POWER_MENU = "lockdown_in_power_menu";
 
-        private static final Validator LOCKDOWN_IN_POWER_MENU_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Backup manager behavioral parameters.
          * This is encoded as a key=value list, separated by commas. Ex:
@@ -8790,9 +8005,6 @@
         @SystemApi
         public static final int VOLUME_HUSH_MUTE = 2;
 
-        private static final Validator VOLUME_HUSH_GESTURE_VALIDATOR =
-                NON_NEGATIVE_INTEGER_VALIDATOR;
-
         /**
          * The number of times (integer) the user has manually enabled battery saver.
          * @hide
@@ -8869,9 +8081,6 @@
         public static final String THEME_CUSTOMIZATION_OVERLAY_PACKAGES =
                 "theme_customization_overlay_packages";
 
-        private static final Validator THEME_CUSTOMIZATION_OVERLAY_PACKAGES_VALIDATOR =
-                JSON_OBJECT_VALIDATOR;
-
         /**
          * Navigation bar mode.
          *  0 = 3 button
@@ -8881,8 +8090,6 @@
          */
         public static final String NAVIGATION_MODE =
                 "navigation_mode";
-        private static final Validator NAVIGATION_MODE_VALIDATOR =
-                new DiscreteValueValidator(new String[] {"0", "1", "2"});
 
         /**
          * Controls whether aware is enabled.
@@ -8890,162 +8097,12 @@
          */
         public static final String AWARE_ENABLED = "aware_enabled";
 
-        private static final Validator AWARE_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Controls whether aware_lock is enabled.
          * @hide
          */
         public static final String AWARE_LOCK_ENABLED = "aware_lock_enabled";
 
-        private static final Validator AWARE_LOCK_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
-        /**
-         * This are the settings to be backed up.
-         *
-         * NOTE: Settings are backed up and restored in the order they appear
-         *       in this array. If you have one setting depending on another,
-         *       make sure that they are ordered appropriately.
-         *
-         * @hide
-         */
-        @UnsupportedAppUsage
-        public static final String[] SETTINGS_TO_BACKUP = {
-            BUGREPORT_IN_POWER_MENU,                            // moved to global
-            ALLOW_MOCK_LOCATION,
-            USB_MASS_STORAGE_ENABLED,                           // moved to global
-            ACCESSIBILITY_DISPLAY_INVERSION_ENABLED,
-            ACCESSIBILITY_DISPLAY_DALTONIZER,
-            ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
-            ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
-            ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED,
-            AUTOFILL_SERVICE,
-            ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
-            ENABLED_ACCESSIBILITY_SERVICES,
-            ENABLED_VR_LISTENERS,
-            TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
-            TOUCH_EXPLORATION_ENABLED,
-            ACCESSIBILITY_ENABLED,
-            ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
-            ACCESSIBILITY_BUTTON_TARGET_COMPONENT,
-            ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
-            ACCESSIBILITY_SHORTCUT_ENABLED,
-            ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN,
-            ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED,
-            ACCESSIBILITY_CAPTIONING_PRESET,
-            ACCESSIBILITY_CAPTIONING_ENABLED,
-            ACCESSIBILITY_CAPTIONING_LOCALE,
-            ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR,
-            ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR,
-            ACCESSIBILITY_CAPTIONING_EDGE_TYPE,
-            ACCESSIBILITY_CAPTIONING_EDGE_COLOR,
-            ACCESSIBILITY_CAPTIONING_TYPEFACE,
-            ACCESSIBILITY_CAPTIONING_FONT_SCALE,
-            ACCESSIBILITY_CAPTIONING_WINDOW_COLOR,
-            TTS_DEFAULT_RATE,
-            TTS_DEFAULT_PITCH,
-            TTS_DEFAULT_SYNTH,
-            TTS_ENABLED_PLUGINS,
-            TTS_DEFAULT_LOCALE,
-            SHOW_IME_WITH_HARD_KEYBOARD,
-            WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,            // moved to global
-            WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,               // moved to global
-            WIFI_NUM_OPEN_NETWORKS_KEPT,                        // moved to global
-            MOUNT_PLAY_NOTIFICATION_SND,
-            MOUNT_UMS_AUTOSTART,
-            MOUNT_UMS_PROMPT,
-            MOUNT_UMS_NOTIFY_ENABLED,
-            DOUBLE_TAP_TO_WAKE,
-            WAKE_GESTURE_ENABLED,
-            LONG_PRESS_TIMEOUT,
-            CAMERA_GESTURE_DISABLED,
-            ACCESSIBILITY_AUTOCLICK_ENABLED,
-            ACCESSIBILITY_AUTOCLICK_DELAY,
-            ACCESSIBILITY_LARGE_POINTER_ICON,
-            PREFERRED_TTY_MODE,
-            ENHANCED_VOICE_PRIVACY_ENABLED,
-            TTY_MODE_ENABLED,
-            RTT_CALLING_MODE,
-            INCALL_POWER_BUTTON_BEHAVIOR,
-            NIGHT_DISPLAY_CUSTOM_START_TIME,
-            NIGHT_DISPLAY_CUSTOM_END_TIME,
-            NIGHT_DISPLAY_COLOR_TEMPERATURE,
-            NIGHT_DISPLAY_AUTO_MODE,
-            DISPLAY_WHITE_BALANCE_ENABLED,
-            SYNC_PARENT_SOUNDS,
-            CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED,
-            CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED,
-            SYSTEM_NAVIGATION_KEYS_ENABLED,
-            QS_TILES,
-            DOZE_ENABLED,
-            DOZE_ALWAYS_ON,
-            DOZE_PICK_UP_GESTURE,
-            DOZE_DOUBLE_TAP_GESTURE,
-            DOZE_TAP_SCREEN_GESTURE,
-            DOZE_WAKE_LOCK_SCREEN_GESTURE,
-            DOZE_WAKE_DISPLAY_GESTURE,
-            NFC_PAYMENT_DEFAULT_COMPONENT,
-            AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN,
-            FACE_UNLOCK_KEYGUARD_ENABLED,
-            SHOW_MEDIA_WHEN_BYPASSING,
-            FACE_UNLOCK_DISMISSES_KEYGUARD,
-            FACE_UNLOCK_APP_ENABLED,
-            FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION,
-            ASSIST_GESTURE_ENABLED,
-            ASSIST_GESTURE_SILENCE_ALERTS_ENABLED,
-            ASSIST_GESTURE_WAKE_ENABLED,
-            VR_DISPLAY_MODE,
-            NOTIFICATION_BADGING,
-            NOTIFICATION_BUBBLES,
-            NOTIFICATION_DISMISS_RTL,
-            QS_AUTO_ADDED_TILES,
-            SCREENSAVER_ENABLED,
-            SCREENSAVER_COMPONENTS,
-            SCREENSAVER_ACTIVATE_ON_DOCK,
-            SCREENSAVER_ACTIVATE_ON_SLEEP,
-            LOCKDOWN_IN_POWER_MENU,
-            SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
-            VOLUME_HUSH_GESTURE,
-            MANUAL_RINGER_TOGGLE_COUNT,
-            HUSH_GESTURE_USED,
-            IN_CALL_NOTIFICATION_ENABLED,
-            LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
-            LOCK_SCREEN_CUSTOM_CLOCK_FACE,
-            LOCK_SCREEN_SHOW_NOTIFICATIONS,
-            LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS,
-            SHOW_NOTIFICATION_SNOOZE,
-            ZEN_DURATION,
-            SHOW_ZEN_UPGRADE_NOTIFICATION,
-            SHOW_ZEN_SETTINGS_SUGGESTION,
-            ZEN_SETTINGS_UPDATED,
-            ZEN_SETTINGS_SUGGESTION_VIEWED,
-            CHARGING_SOUNDS_ENABLED,
-            CHARGING_VIBRATION_ENABLED,
-            ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS,
-            ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS,
-            NOTIFICATION_NEW_INTERRUPTION_MODEL,
-            TRUST_AGENTS_EXTEND_UNLOCK,
-            UI_NIGHT_MODE,
-            LOCK_SCREEN_WHEN_TRUST_LOST,
-            SKIP_GESTURE,
-            SKIP_DIRECTION,
-            SILENCE_GESTURE,
-            THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
-            NAVIGATION_MODE,
-            AWARE_ENABLED,
-            SKIP_GESTURE_COUNT,
-            SKIP_TOUCH_COUNT,
-            SILENCE_ALARMS_GESTURE_COUNT,
-            SILENCE_CALL_GESTURE_COUNT,
-            SILENCE_TIMER_GESTURE_COUNT,
-            SILENCE_ALARMS_TOUCH_COUNT,
-            SILENCE_CALL_TOUCH_COUNT,
-            SILENCE_TIMER_TOUCH_COUNT,
-            DARK_MODE_DIALOG_SEEN,
-            GLOBAL_ACTIONS_PANEL_ENABLED,
-            AWARE_LOCK_ENABLED
-        };
-
         /**
          * The settings values which should only be restored if the target device is the
          * same as the source device
@@ -9061,201 +8118,6 @@
         };
 
         /**
-         * All settings in {@link SETTINGS_TO_BACKUP} and {@link DEVICE_SPECIFIC_SETTINGS_TO_BACKUP}
-         * array *must* have a non-null validator, otherwise they won't be restored.
-         *
-         * @hide
-         */
-        public static final Map<String, Validator> VALIDATORS = new ArrayMap<>();
-        static {
-            VALIDATORS.put(BUGREPORT_IN_POWER_MENU, BUGREPORT_IN_POWER_MENU_VALIDATOR);
-            VALIDATORS.put(ALLOW_MOCK_LOCATION, ALLOW_MOCK_LOCATION_VALIDATOR);
-            VALIDATORS.put(USB_MASS_STORAGE_ENABLED, USB_MASS_STORAGE_ENABLED_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_DISPLAY_INVERSION_ENABLED,
-                    ACCESSIBILITY_DISPLAY_INVERSION_ENABLED_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_DISPLAY_DALTONIZER,
-                    ACCESSIBILITY_DISPLAY_DALTONIZER_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
-                    ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
-                    ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED,
-                    ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED_VALIDATOR);
-            VALIDATORS.put(AUTOFILL_SERVICE, AUTOFILL_SERVICE_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
-                    ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE_VALIDATOR);
-            VALIDATORS.put(ENABLED_ACCESSIBILITY_SERVICES,
-                    ENABLED_ACCESSIBILITY_SERVICES_VALIDATOR);
-            VALIDATORS.put(ENABLED_VR_LISTENERS, ENABLED_VR_LISTENERS_VALIDATOR);
-            VALIDATORS.put(TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
-                    TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES_VALIDATOR);
-            VALIDATORS.put(TOUCH_EXPLORATION_ENABLED, TOUCH_EXPLORATION_ENABLED_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_ENABLED, ACCESSIBILITY_ENABLED_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
-                    ACCESSIBILITY_SHORTCUT_TARGET_SERVICE_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_BUTTON_TARGET_COMPONENT,
-                    ACCESSIBILITY_BUTTON_TARGET_COMPONENT_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
-                    ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_SHORTCUT_ENABLED,
-                    ACCESSIBILITY_SHORTCUT_ENABLED_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN,
-                    ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED,
-                    ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_CAPTIONING_PRESET,
-                    ACCESSIBILITY_CAPTIONING_PRESET_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_CAPTIONING_ENABLED,
-                    ACCESSIBILITY_CAPTIONING_ENABLED_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_CAPTIONING_LOCALE,
-                    ACCESSIBILITY_CAPTIONING_LOCALE_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR,
-                    ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR,
-                    ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_CAPTIONING_EDGE_TYPE,
-                    ACCESSIBILITY_CAPTIONING_EDGE_TYPE_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_CAPTIONING_EDGE_COLOR,
-                    ACCESSIBILITY_CAPTIONING_EDGE_COLOR_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_CAPTIONING_TYPEFACE,
-                    ACCESSIBILITY_CAPTIONING_TYPEFACE_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_CAPTIONING_FONT_SCALE,
-                    ACCESSIBILITY_CAPTIONING_FONT_SCALE_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_CAPTIONING_WINDOW_COLOR,
-                    ACCESSIBILITY_CAPTIONING_WINDOW_COLOR_VALIDATOR);
-            VALIDATORS.put(TTS_DEFAULT_RATE, TTS_DEFAULT_RATE_VALIDATOR);
-            VALIDATORS.put(TTS_DEFAULT_PITCH, TTS_DEFAULT_PITCH_VALIDATOR);
-            VALIDATORS.put(TTS_DEFAULT_SYNTH, TTS_DEFAULT_SYNTH_VALIDATOR);
-            VALIDATORS.put(TTS_ENABLED_PLUGINS, TTS_ENABLED_PLUGINS_VALIDATOR);
-            VALIDATORS.put(TTS_DEFAULT_LOCALE, TTS_DEFAULT_LOCALE_VALIDATOR);
-            VALIDATORS.put(SHOW_IME_WITH_HARD_KEYBOARD, SHOW_IME_WITH_HARD_KEYBOARD_VALIDATOR);
-            VALIDATORS.put(WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
-                    WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON_VALIDATOR);
-            VALIDATORS.put(WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,
-                    WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY_VALIDATOR);
-            VALIDATORS.put(WIFI_NUM_OPEN_NETWORKS_KEPT, WIFI_NUM_OPEN_NETWORKS_KEPT_VALIDATOR);
-            VALIDATORS.put(MOUNT_PLAY_NOTIFICATION_SND, MOUNT_PLAY_NOTIFICATION_SND_VALIDATOR);
-            VALIDATORS.put(MOUNT_UMS_AUTOSTART, MOUNT_UMS_AUTOSTART_VALIDATOR);
-            VALIDATORS.put(MOUNT_UMS_PROMPT, MOUNT_UMS_PROMPT_VALIDATOR);
-            VALIDATORS.put(MOUNT_UMS_NOTIFY_ENABLED, MOUNT_UMS_NOTIFY_ENABLED_VALIDATOR);
-            VALIDATORS.put(DOUBLE_TAP_TO_WAKE, DOUBLE_TAP_TO_WAKE_VALIDATOR);
-            VALIDATORS.put(WAKE_GESTURE_ENABLED, WAKE_GESTURE_ENABLED_VALIDATOR);
-            VALIDATORS.put(LONG_PRESS_TIMEOUT, LONG_PRESS_TIMEOUT_VALIDATOR);
-            VALIDATORS.put(CAMERA_GESTURE_DISABLED, CAMERA_GESTURE_DISABLED_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_AUTOCLICK_ENABLED,
-                    ACCESSIBILITY_AUTOCLICK_ENABLED_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_AUTOCLICK_DELAY, ACCESSIBILITY_AUTOCLICK_DELAY_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_LARGE_POINTER_ICON,
-                    ACCESSIBILITY_LARGE_POINTER_ICON_VALIDATOR);
-            VALIDATORS.put(PREFERRED_TTY_MODE, PREFERRED_TTY_MODE_VALIDATOR);
-            VALIDATORS.put(ENHANCED_VOICE_PRIVACY_ENABLED,
-                    ENHANCED_VOICE_PRIVACY_ENABLED_VALIDATOR);
-            VALIDATORS.put(TTY_MODE_ENABLED, TTY_MODE_ENABLED_VALIDATOR);
-            VALIDATORS.put(RTT_CALLING_MODE, RTT_CALLING_MODE_VALIDATOR);
-            VALIDATORS.put(INCALL_POWER_BUTTON_BEHAVIOR, INCALL_POWER_BUTTON_BEHAVIOR_VALIDATOR);
-            VALIDATORS.put(NIGHT_DISPLAY_CUSTOM_START_TIME,
-                    NIGHT_DISPLAY_CUSTOM_START_TIME_VALIDATOR);
-            VALIDATORS.put(NIGHT_DISPLAY_CUSTOM_END_TIME, NIGHT_DISPLAY_CUSTOM_END_TIME_VALIDATOR);
-            VALIDATORS.put(NIGHT_DISPLAY_COLOR_TEMPERATURE,
-                    NIGHT_DISPLAY_COLOR_TEMPERATURE_VALIDATOR);
-            VALIDATORS.put(NIGHT_DISPLAY_AUTO_MODE, NIGHT_DISPLAY_AUTO_MODE_VALIDATOR);
-            VALIDATORS.put(DISPLAY_WHITE_BALANCE_ENABLED, DISPLAY_WHITE_BALANCE_ENABLED_VALIDATOR);
-            VALIDATORS.put(SYNC_PARENT_SOUNDS, SYNC_PARENT_SOUNDS_VALIDATOR);
-            VALIDATORS.put(CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED,
-                    CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED_VALIDATOR);
-            VALIDATORS.put(CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED,
-                    CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED_VALIDATOR);
-            VALIDATORS.put(SYSTEM_NAVIGATION_KEYS_ENABLED,
-                    SYSTEM_NAVIGATION_KEYS_ENABLED_VALIDATOR);
-            VALIDATORS.put(QS_TILES, QS_TILES_VALIDATOR);
-            VALIDATORS.put(DOZE_ENABLED, DOZE_ENABLED_VALIDATOR);
-            VALIDATORS.put(DOZE_ALWAYS_ON, DOZE_ALWAYS_ON_VALIDATOR);
-            VALIDATORS.put(DOZE_PICK_UP_GESTURE, DOZE_PICK_UP_GESTURE_VALIDATOR);
-            VALIDATORS.put(DOZE_DOUBLE_TAP_GESTURE, DOZE_DOUBLE_TAP_GESTURE_VALIDATOR);
-            VALIDATORS.put(DOZE_TAP_SCREEN_GESTURE, DOZE_TAP_SCREEN_GESTURE_VALIDATOR);
-            VALIDATORS.put(DOZE_WAKE_LOCK_SCREEN_GESTURE, DOZE_WAKE_LOCK_SCREEN_GESTURE_VALIDATOR);
-            VALIDATORS.put(DOZE_WAKE_DISPLAY_GESTURE, DOZE_WAKE_DISPLAY_GESTURE_VALIDATOR);
-            VALIDATORS.put(NFC_PAYMENT_DEFAULT_COMPONENT, NFC_PAYMENT_DEFAULT_COMPONENT_VALIDATOR);
-            VALIDATORS.put(AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN,
-                    AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN_VALIDATOR);
-            VALIDATORS.put(FACE_UNLOCK_KEYGUARD_ENABLED, FACE_UNLOCK_KEYGUARD_ENABLED_VALIDATOR);
-            VALIDATORS.put(FACE_UNLOCK_DISMISSES_KEYGUARD,
-                    FACE_UNLOCK_DISMISSES_KEYGUARD_VALIDATOR);
-            VALIDATORS.put(SHOW_MEDIA_WHEN_BYPASSING, SHOW_MEDIA_WHEN_BYPASSING_VALIDATOR);
-            VALIDATORS.put(FACE_UNLOCK_APP_ENABLED, FACE_UNLOCK_APP_ENABLED_VALIDATOR);
-            VALIDATORS.put(FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION,
-                    FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION_VALIDATOR);
-            VALIDATORS.put(ASSIST_GESTURE_ENABLED, ASSIST_GESTURE_ENABLED_VALIDATOR);
-            VALIDATORS.put(ASSIST_GESTURE_SILENCE_ALERTS_ENABLED,
-                    ASSIST_GESTURE_SILENCE_ALERTS_ENABLED_VALIDATOR);
-            VALIDATORS.put(ASSIST_GESTURE_WAKE_ENABLED, ASSIST_GESTURE_WAKE_ENABLED_VALIDATOR);
-            VALIDATORS.put(VR_DISPLAY_MODE, VR_DISPLAY_MODE_VALIDATOR);
-            VALIDATORS.put(NOTIFICATION_BADGING, NOTIFICATION_BADGING_VALIDATOR);
-            VALIDATORS.put(NOTIFICATION_BUBBLES, NOTIFICATION_BUBBLES_VALIDATOR);
-            VALIDATORS.put(NOTIFICATION_DISMISS_RTL, NOTIFICATION_DISMISS_RTL_VALIDATOR);
-            VALIDATORS.put(QS_AUTO_ADDED_TILES, QS_AUTO_ADDED_TILES_VALIDATOR);
-            VALIDATORS.put(SCREENSAVER_ENABLED, SCREENSAVER_ENABLED_VALIDATOR);
-            VALIDATORS.put(SCREENSAVER_COMPONENTS, SCREENSAVER_COMPONENTS_VALIDATOR);
-            VALIDATORS.put(SCREENSAVER_ACTIVATE_ON_DOCK, SCREENSAVER_ACTIVATE_ON_DOCK_VALIDATOR);
-            VALIDATORS.put(SCREENSAVER_ACTIVATE_ON_SLEEP, SCREENSAVER_ACTIVATE_ON_SLEEP_VALIDATOR);
-            VALIDATORS.put(LOCKDOWN_IN_POWER_MENU, LOCKDOWN_IN_POWER_MENU_VALIDATOR);
-            VALIDATORS.put(SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
-                    SHOW_FIRST_CRASH_DIALOG_DEV_OPTION_VALIDATOR);
-            VALIDATORS.put(VOLUME_HUSH_GESTURE, VOLUME_HUSH_GESTURE_VALIDATOR);
-            VALIDATORS.put(ENABLED_NOTIFICATION_LISTENERS,
-                    ENABLED_NOTIFICATION_LISTENERS_VALIDATOR); //legacy restore setting
-            VALIDATORS.put(ENABLED_NOTIFICATION_ASSISTANT,
-                    ENABLED_NOTIFICATION_ASSISTANT_VALIDATOR); //legacy restore setting
-            VALIDATORS.put(ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
-                    ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES_VALIDATOR); //legacy restore setting
-            VALIDATORS.put(HUSH_GESTURE_USED, HUSH_GESTURE_USED_VALIDATOR);
-            VALIDATORS.put(MANUAL_RINGER_TOGGLE_COUNT, MANUAL_RINGER_TOGGLE_COUNT_VALIDATOR);
-            VALIDATORS.put(IN_CALL_NOTIFICATION_ENABLED, IN_CALL_NOTIFICATION_ENABLED_VALIDATOR);
-            VALIDATORS.put(LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, BOOLEAN_VALIDATOR);
-            VALIDATORS.put(LOCK_SCREEN_SHOW_NOTIFICATIONS, BOOLEAN_VALIDATOR);
-            VALIDATORS.put(LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, BOOLEAN_VALIDATOR);
-            VALIDATORS.put(SHOW_NOTIFICATION_SNOOZE, BOOLEAN_VALIDATOR);
-            VALIDATORS.put(ZEN_DURATION, ZEN_DURATION_VALIDATOR);
-            VALIDATORS.put(SHOW_ZEN_UPGRADE_NOTIFICATION, BOOLEAN_VALIDATOR);
-            VALIDATORS.put(SHOW_ZEN_SETTINGS_SUGGESTION, BOOLEAN_VALIDATOR);
-            VALIDATORS.put(ZEN_SETTINGS_UPDATED, BOOLEAN_VALIDATOR);
-            VALIDATORS.put(ZEN_SETTINGS_SUGGESTION_VIEWED, BOOLEAN_VALIDATOR);
-            VALIDATORS.put(CHARGING_SOUNDS_ENABLED, BOOLEAN_VALIDATOR);
-            VALIDATORS.put(CHARGING_VIBRATION_ENABLED, BOOLEAN_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS,
-                    NON_NEGATIVE_INTEGER_VALIDATOR);
-            VALIDATORS.put(ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS, NON_NEGATIVE_INTEGER_VALIDATOR);
-            VALIDATORS.put(USER_SETUP_COMPLETE, BOOLEAN_VALIDATOR);
-            VALIDATORS.put(ASSIST_GESTURE_SETUP_COMPLETE, BOOLEAN_VALIDATOR);
-            VALIDATORS.put(NOTIFICATION_NEW_INTERRUPTION_MODEL, BOOLEAN_VALIDATOR);
-            VALIDATORS.put(TRUST_AGENTS_EXTEND_UNLOCK, TRUST_AGENTS_EXTEND_UNLOCK_VALIDATOR);
-            VALIDATORS.put(LOCK_SCREEN_CUSTOM_CLOCK_FACE, LOCK_SCREEN_CUSTOM_CLOCK_FACE_VALIDATOR);
-            VALIDATORS.put(LOCK_SCREEN_WHEN_TRUST_LOST, LOCK_SCREEN_WHEN_TRUST_LOST_VALIDATOR);
-            VALIDATORS.put(SKIP_GESTURE, SKIP_GESTURE_VALIDATOR);
-            VALIDATORS.put(SKIP_DIRECTION, SKIP_DIRECTION_VALIDATOR);
-            VALIDATORS.put(SKIP_DIRECTION, SKIP_DIRECTION_VALIDATOR);
-            VALIDATORS.put(SILENCE_GESTURE, SILENCE_GESTURE_VALIDATOR);
-            VALIDATORS.put(THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
-                    THEME_CUSTOMIZATION_OVERLAY_PACKAGES_VALIDATOR);
-            VALIDATORS.put(NAVIGATION_MODE, NAVIGATION_MODE_VALIDATOR);
-            VALIDATORS.put(AWARE_ENABLED, AWARE_ENABLED_VALIDATOR);
-            VALIDATORS.put(SKIP_GESTURE_COUNT, SKIP_GESTURE_COUNT_VALIDATOR);
-            VALIDATORS.put(SKIP_TOUCH_COUNT, SKIP_GESTURE_COUNT_VALIDATOR);
-            VALIDATORS.put(SILENCE_ALARMS_GESTURE_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR);
-            VALIDATORS.put(SILENCE_TIMER_GESTURE_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR);
-            VALIDATORS.put(SILENCE_CALL_GESTURE_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR);
-            VALIDATORS.put(SILENCE_ALARMS_TOUCH_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR);
-            VALIDATORS.put(SILENCE_TIMER_TOUCH_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR);
-            VALIDATORS.put(SILENCE_CALL_TOUCH_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR);
-            VALIDATORS.put(ODI_CAPTIONS_ENABLED, ODI_CAPTIONS_ENABLED_VALIDATOR);
-            VALIDATORS.put(DARK_MODE_DIALOG_SEEN, BOOLEAN_VALIDATOR);
-            VALIDATORS.put(UI_NIGHT_MODE, UI_NIGHT_MODE_VALIDATOR);
-            VALIDATORS.put(GLOBAL_ACTIONS_PANEL_ENABLED, GLOBAL_ACTIONS_PANEL_ENABLED_VALIDATOR);
-            VALIDATORS.put(AWARE_LOCK_ENABLED, AWARE_LOCK_ENABLED_VALIDATOR);
-            VALIDATORS.put(DISPLAY_DENSITY_FORCED, DISPLAY_DENSITY_FORCED_VALIDATOR);
-        }
-
-        /**
          * Keys we no longer back up under the current schema, but want to continue to
          * process when restoring historical backup datasets.
          *
@@ -9387,8 +8249,6 @@
          */
         public static final String APPLY_RAMPING_RINGER = "apply_ramping_ringer";
 
-        private static final Validator APPLY_RAMPING_RINGER_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Setting whether the global gesture for enabling accessibility is enabled.
          * If this gesture is enabled the user will be able to perfrom it to enable
@@ -9516,16 +8376,12 @@
          */
         public static final String AUTO_TIME = "auto_time";
 
-        private static final Validator AUTO_TIME_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Value to specify if the user prefers the time zone
          * to be automatically fetched from the network (NITZ). 1=yes, 0=no
          */
         public static final String AUTO_TIME_ZONE = "auto_time_zone";
 
-        private static final Validator AUTO_TIME_ZONE_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * URI for the car dock "in" event sound.
          * @hide
@@ -9556,8 +8412,6 @@
          */
         public static final String DOCK_SOUNDS_ENABLED = "dock_sounds_enabled";
 
-        private static final Validator DOCK_SOUNDS_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Whether to play a sound for dock events, only when an accessibility service is on.
          * @hide
@@ -9595,8 +8449,6 @@
          */
         public static final String POWER_SOUNDS_ENABLED = "power_sounds_enabled";
 
-        private static final Validator POWER_SOUNDS_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * URI for the "wireless charging started" and "wired charging started" sound.
          * @hide
@@ -9612,8 +8464,6 @@
         @Deprecated
         public static final String CHARGING_SOUNDS_ENABLED = "charging_sounds_enabled";
 
-        private static final Validator CHARGING_SOUNDS_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Whether to vibrate for wireless charging events.
          * @deprecated Use {@link android.provider.Settings.Secure#CHARGING_VIBRATION_ENABLED}
@@ -9622,8 +8472,6 @@
         @Deprecated
         public static final String CHARGING_VIBRATION_ENABLED = "charging_vibration_enabled";
 
-        private static final Validator CHARGING_VIBRATION_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Whether we keep the device on while the device is plugged in.
          * Supported values are:
@@ -9637,30 +8485,6 @@
          */
         public static final String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
 
-        private static final Validator STAY_ON_WHILE_PLUGGED_IN_VALIDATOR = new Validator() {
-            @Override
-            public boolean validate(@Nullable String value) {
-                try {
-                    int val = Integer.parseInt(value);
-                    return (val == 0)
-                            || (val == BatteryManager.BATTERY_PLUGGED_AC)
-                            || (val == BatteryManager.BATTERY_PLUGGED_USB)
-                            || (val == BatteryManager.BATTERY_PLUGGED_WIRELESS)
-                            || (val == (BatteryManager.BATTERY_PLUGGED_AC
-                                    | BatteryManager.BATTERY_PLUGGED_USB))
-                            || (val == (BatteryManager.BATTERY_PLUGGED_AC
-                                    | BatteryManager.BATTERY_PLUGGED_WIRELESS))
-                            || (val == (BatteryManager.BATTERY_PLUGGED_USB
-                                    | BatteryManager.BATTERY_PLUGGED_WIRELESS))
-                            || (val == (BatteryManager.BATTERY_PLUGGED_AC
-                                    | BatteryManager.BATTERY_PLUGGED_USB
-                                    | BatteryManager.BATTERY_PLUGGED_WIRELESS));
-                } catch (NumberFormatException e) {
-                    return false;
-                }
-            }
-        };
-
         /**
          * When the user has enable the option to have a "bug report" command
          * in the power menu.
@@ -9668,8 +8492,6 @@
          */
         public static final String BUGREPORT_IN_POWER_MENU = "bugreport_in_power_menu";
 
-        private static final Validator BUGREPORT_IN_POWER_MENU_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Whether ADB is enabled.
          */
@@ -9700,8 +8522,6 @@
          */
         public static final String BLUETOOTH_ON = "bluetooth_on";
 
-        private static final Validator BLUETOOTH_ON_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * CDMA Cell Broadcast SMS
          *                            0 = CDMA Cell Broadcast SMS disabled
@@ -10426,8 +9246,6 @@
         */
        public static final String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
 
-       private static final Validator USB_MASS_STORAGE_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
        /**
         * If this setting is set (to anything), then all references
         * to Gmail on the device must change to Google Mail.
@@ -10580,9 +9398,6 @@
        public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON =
                "wifi_networks_available_notification_on";
 
-       private static final Validator WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON_VALIDATOR =
-               BOOLEAN_VALIDATOR;
-
        /**
         * {@hide}
         */
@@ -10596,9 +9411,6 @@
        public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY =
                "wifi_networks_available_repeat_delay";
 
-       private static final Validator WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY_VALIDATOR =
-               NON_NEGATIVE_INTEGER_VALIDATOR;
-
        /**
         * 802.11 country code in ISO 3166 format
         * @hide
@@ -10628,9 +9440,6 @@
         */
        public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = "wifi_num_open_networks_kept";
 
-       private static final Validator WIFI_NUM_OPEN_NETWORKS_KEPT_VALIDATOR =
-               NON_NEGATIVE_INTEGER_VALIDATOR;
-
        /**
         * Whether the Wi-Fi should be on.  Only the Wi-Fi service should touch this.
         */
@@ -10669,8 +9478,6 @@
          */
         public static final String SOFT_AP_TIMEOUT_ENABLED = "soft_ap_timeout_enabled";
 
-        private static final Validator SOFT_AP_TIMEOUT_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Value to specify if Wi-Fi Wakeup feature is enabled.
          *
@@ -10680,8 +9487,6 @@
         @SystemApi
         public static final String WIFI_WAKEUP_ENABLED = "wifi_wakeup_enabled";
 
-        private static final Validator WIFI_WAKEUP_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Value to specify whether network quality scores and badging should be shown in the UI.
          *
@@ -10717,8 +9522,6 @@
         public static final String NETWORK_RECOMMENDATIONS_ENABLED =
                 "network_recommendations_enabled";
 
-        private static final Validator NETWORK_RECOMMENDATIONS_ENABLED_VALIDATOR =
-                new DiscreteValueValidator(new String[] {"-1", "0", "1"});
 
         /**
          * Which package name to use for network recommendations. If null, network recommendations
@@ -10743,13 +9546,6 @@
         @TestApi
         public static final String USE_OPEN_WIFI_PACKAGE = "use_open_wifi_package";
 
-        private static final Validator USE_OPEN_WIFI_PACKAGE_VALIDATOR = new Validator() {
-            @Override
-            public boolean validate(@Nullable String value) {
-                return (value == null) || PACKAGE_NAME_VALIDATOR.validate(value);
-            }
-        };
-
         /**
          * The number of milliseconds the {@link com.android.server.NetworkScoreService}
          * will give a recommendation request to complete before returning a default response.
@@ -10781,8 +9577,6 @@
          */
         public static final String WIFI_SCAN_THROTTLE_ENABLED = "wifi_scan_throttle_enabled";
 
-        private static final Validator WIFI_SCAN_THROTTLE_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
         * Settings to allow BLE scans to be enabled even when Bluetooth is turned off for
         * connectivity.
@@ -10888,9 +9682,6 @@
        public static final String WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED =
                "wifi_watchdog_poor_network_test_enabled";
 
-       private static final Validator WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED_VALIDATOR =
-               ANY_STRING_VALIDATOR;
-
        /**
         * Setting to turn on suspend optimizations at screen off on Wi-Fi. Enabled by default and
         * needs to be set to 0 to disable it.
@@ -10974,9 +9765,6 @@
         public static final String WIFI_PNO_FREQUENCY_CULLING_ENABLED =
                 "wifi_pno_frequency_culling_enabled";
 
-        private static final Validator WIFI_PNO_FREQUENCY_CULLING_ENABLED_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * Setting to enable including recency information when determining pno network priorities.
          * Disabled by default, and setting it to 1 will enable it.
@@ -10986,9 +9774,6 @@
         public static final String WIFI_PNO_RECENCY_SORTING_ENABLED =
                 "wifi_pno_recency_sorting_enabled";
 
-        private static final Validator WIFI_PNO_RECENCY_SORTING_ENABLED_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * Setting to enable the Wi-Fi link probing.
          * Enabled by default, and setting it to 0 will disable it.
@@ -10998,9 +9783,6 @@
         public static final String WIFI_LINK_PROBING_ENABLED =
                 "wifi_link_probing_enabled";
 
-        private static final Validator WIFI_LINK_PROBING_ENABLED_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
        /**
         * The maximum number of times we will retry a connection to an access
         * point for which we have failed in acquiring an IP address from DHCP.
@@ -11540,15 +10322,11 @@
          */
         public static final String PRIVATE_DNS_MODE = "private_dns_mode";
 
-        private static final Validator PRIVATE_DNS_MODE_VALIDATOR = ANY_STRING_VALIDATOR;
-
         /**
          * @hide
          */
         public static final String PRIVATE_DNS_SPECIFIER = "private_dns_specifier";
 
-        private static final Validator PRIVATE_DNS_SPECIFIER_VALIDATOR = ANY_STRING_VALIDATOR;
-
         /**
           * Forced override of the default mode (hardcoded as "automatic", nee "opportunistic").
           * This allows changing the default mode without effectively disabling other modes,
@@ -12291,9 +11069,6 @@
         public static final String APP_AUTO_RESTRICTION_ENABLED =
                 "app_auto_restriction_enabled";
 
-        private static final Validator APP_AUTO_RESTRICTION_ENABLED_VALIDATOR =
-                BOOLEAN_VALIDATOR;
-
         /**
          * Feature flag to enable or disable the Forced App Standby feature.
          * Type: int (0 for false, 1 for true)
@@ -12568,9 +11343,6 @@
          */
         public static final String EMERGENCY_TONE = "emergency_tone";
 
-        private static final Validator EMERGENCY_TONE_VALIDATOR =
-                new DiscreteValueValidator(new String[] {"0", "1", "2"});
-
         /**
          * CDMA only settings
          * Whether the auto retry is enabled. The value is
@@ -12579,8 +11351,6 @@
          */
         public static final String CALL_AUTO_RETRY = "call_auto_retry";
 
-        private static final Validator CALL_AUTO_RETRY_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * A setting that can be read whether the emergency affordance is currently needed.
          * The value is a boolean (1 or 0).
@@ -12598,9 +11368,6 @@
         public static final String ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS =
                 "enable_automatic_system_server_heap_dumps";
 
-        private static final Validator ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_VALIDATOR =
-                new DiscreteValueValidator(new String[] {"0", "1"});
-
         /**
          * See RIL_PreferredNetworkType in ril.h
          * @hide
@@ -12792,9 +11559,6 @@
         public static final String LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL =
                 "low_power_sticky_auto_disable_level";
 
-        private static final Validator LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL_VALIDATOR =
-                new InclusiveIntegerRangeValidator(0, 100);
-
         /**
          * Whether sticky battery saver should be deactivated once the battery level has reached the
          * threshold specified by {@link #LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL}.
@@ -12804,9 +11568,6 @@
         public static final String LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED =
                 "low_power_sticky_auto_disable_enabled";
 
-        private static final Validator LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED_VALIDATOR =
-                new DiscreteValueValidator(new String[] {"0", "1"});
-
         /**
          * Battery level [1-100] at which low power mode automatically turns on.
          * If 0, it will not automatically turn on. For Q and newer, it will only automatically
@@ -12819,9 +11580,6 @@
          */
         public static final String LOW_POWER_MODE_TRIGGER_LEVEL = "low_power_trigger_level";
 
-        private static final Validator LOW_POWER_MODE_TRIGGER_LEVEL_VALIDATOR =
-                new InclusiveIntegerRangeValidator(0, 100);
-
         /**
          * Whether battery saver is currently set to trigger based on percentage, dynamic power
          * savings trigger, or none. See {@link AutoPowerSaveModeTriggers} for
@@ -12832,9 +11590,6 @@
         @TestApi
         public static final String AUTOMATIC_POWER_SAVE_MODE = "automatic_power_save_mode";
 
-        private static final Validator AUTOMATIC_POWER_SAVE_MODE_VALIDATOR =
-                new DiscreteValueValidator(new String[] {"0", "1"});
-
         /**
          * The setting that backs the disable threshold for the setPowerSavingsWarning api in
          * PowerManager
@@ -12845,8 +11600,6 @@
         @TestApi
         public static final String DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD =
                 "dynamic_power_savings_disable_threshold";
-        private static final Validator DYNAMIC_POWER_SAVINGS_VALIDATOR =
-                new InclusiveIntegerRangeValidator(0, 100);
 
         /**
          * The setting which backs the setDynamicPowerSaveHint api in PowerManager.
@@ -12934,8 +11687,6 @@
          */
         public static final String DOCK_AUDIO_MEDIA_ENABLED = "dock_audio_media_enabled";
 
-        private static final Validator DOCK_AUDIO_MEDIA_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * The surround sound formats AC3, DTS or IEC61937 are
          * available for use if they are detected.
@@ -12995,9 +11746,6 @@
          */
         public static final String ENCODED_SURROUND_OUTPUT = "encoded_surround_output";
 
-        private static final Validator ENCODED_SURROUND_OUTPUT_VALIDATOR =
-                new DiscreteValueValidator(new String[] {"0", "1", "2", "3"});
-
         /**
          * Surround sounds formats that are enabled when ENCODED_SURROUND_OUTPUT is set to
          * ENCODED_SURROUND_OUTPUT_MANUAL. Encoded as comma separated list. Allowed values
@@ -13010,32 +11758,6 @@
         public static final String ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS =
                 "encoded_surround_output_enabled_formats";
 
-        private static final Validator ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS_VALIDATOR =
-                new Validator() {
-            @Override
-            public boolean validate(@Nullable String value) {
-                try {
-                    String[] surroundFormats = TextUtils.split(value, ",");
-                    for (String format : surroundFormats) {
-                        int audioFormat = Integer.valueOf(format);
-                        boolean isSurroundFormat = false;
-                        for (int sf : AudioFormat.SURROUND_SOUND_ENCODING) {
-                            if (sf == audioFormat) {
-                                isSurroundFormat = true;
-                                break;
-                            }
-                        }
-                        if (!isSurroundFormat) {
-                            return false;
-                        }
-                    }
-                    return true;
-                } catch (NumberFormatException e) {
-                    return false;
-                }
-            }
-        };
-
         /**
          * Persisted safe headphone volume management state by AudioService
          * @hide
@@ -13278,8 +12000,6 @@
         @Deprecated
         public static final String ZEN_DURATION = "zen_duration";
 
-        private static final Validator ZEN_DURATION_VALIDATOR = ANY_INTEGER_VALIDATOR;
-
         /**
          * @deprecated Use {@link android.provider.Settings.Secure#ZEN_DURATION_PROMPT} instead
          * @hide
@@ -13736,8 +12456,6 @@
          */
         public static final String AWARE_ALLOWED = "aware_allowed";
 
-        private static final Validator AWARE_ALLOWED_VALIDATOR = BOOLEAN_VALIDATOR;
-
         /**
          * Overrides internal R.integer.config_longPressOnPowerBehavior.
          * Allowable values detailed in frameworks/base/core/res/res/values/config.xml.
@@ -13746,8 +12464,6 @@
          */
         public static final String POWER_BUTTON_LONG_PRESS =
                 "power_button_long_press";
-        private static final Validator POWER_BUTTON_LONG_PRESS_VALIDATOR =
-                new InclusiveIntegerRangeValidator(0, 5);
 
         /**
          * Overrides internal R.integer.config_veryLongPressOnPowerBehavior.
@@ -13757,126 +12473,6 @@
          */
         public static final String POWER_BUTTON_VERY_LONG_PRESS =
                 "power_button_very_long_press";
-        private static final Validator POWER_BUTTON_VERY_LONG_PRESS_VALIDATOR =
-                new InclusiveIntegerRangeValidator(0, 1);
-
-        /**
-         * Settings to backup. This is here so that it's in the same place as the settings
-         * keys and easy to update.
-         *
-         * These keys may be mentioned in the SETTINGS_TO_BACKUP arrays in System
-         * and Secure as well.  This is because those tables drive both backup and
-         * restore, and restore needs to properly whitelist keys that used to live
-         * in those namespaces.  The keys will only actually be backed up / restored
-         * if they are also mentioned in this table (Global.SETTINGS_TO_BACKUP).
-         *
-         * NOTE: Settings are backed up and restored in the order they appear
-         *       in this array. If you have one setting depending on another,
-         *       make sure that they are ordered appropriately.
-         *
-         * NOTE: This table should only be used for settings which should be restored
-         *       between different types of devices {@see #DEVICE_SPECIFIC_SETTINGS_TO_BACKUP}
-         *
-         * @hide
-         */
-        public static final String[] SETTINGS_TO_BACKUP = {
-            APPLY_RAMPING_RINGER,
-            BUGREPORT_IN_POWER_MENU,
-            STAY_ON_WHILE_PLUGGED_IN,
-            APP_AUTO_RESTRICTION_ENABLED,
-            AUTO_TIME,
-            AUTO_TIME_ZONE,
-            POWER_SOUNDS_ENABLED,
-            DOCK_SOUNDS_ENABLED,
-            CHARGING_SOUNDS_ENABLED,
-            USB_MASS_STORAGE_ENABLED,
-            NETWORK_RECOMMENDATIONS_ENABLED,
-            WIFI_WAKEUP_ENABLED,
-            WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
-            USE_OPEN_WIFI_PACKAGE,
-            WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED,
-            EMERGENCY_TONE,
-            CALL_AUTO_RETRY,
-            DOCK_AUDIO_MEDIA_ENABLED,
-            ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS,
-            ENCODED_SURROUND_OUTPUT,
-            ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS,
-            LOW_POWER_MODE_TRIGGER_LEVEL,
-            LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED,
-            LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL,
-            BLUETOOTH_ON,
-            PRIVATE_DNS_MODE,
-            PRIVATE_DNS_SPECIFIER,
-            SOFT_AP_TIMEOUT_ENABLED,
-            ZEN_DURATION,
-            CHARGING_VIBRATION_ENABLED,
-            AWARE_ALLOWED,
-        };
-
-        /**
-         * All settings in {@link SETTINGS_TO_BACKUP} array *must* have a non-null validator,
-         * otherwise they won't be restored.
-         *
-         * @hide
-         */
-        public static final Map<String, Validator> VALIDATORS = new ArrayMap<>();
-
-        static {
-            VALIDATORS.put(APPLY_RAMPING_RINGER, APPLY_RAMPING_RINGER_VALIDATOR);
-            VALIDATORS.put(BUGREPORT_IN_POWER_MENU, BUGREPORT_IN_POWER_MENU_VALIDATOR);
-            VALIDATORS.put(STAY_ON_WHILE_PLUGGED_IN, STAY_ON_WHILE_PLUGGED_IN_VALIDATOR);
-            VALIDATORS.put(AUTO_TIME, AUTO_TIME_VALIDATOR);
-            VALIDATORS.put(AUTO_TIME_ZONE, AUTO_TIME_ZONE_VALIDATOR);
-            VALIDATORS.put(POWER_SOUNDS_ENABLED, POWER_SOUNDS_ENABLED_VALIDATOR);
-            VALIDATORS.put(DOCK_SOUNDS_ENABLED, DOCK_SOUNDS_ENABLED_VALIDATOR);
-            VALIDATORS.put(CHARGING_SOUNDS_ENABLED, CHARGING_SOUNDS_ENABLED_VALIDATOR);
-            VALIDATORS.put(USB_MASS_STORAGE_ENABLED, USB_MASS_STORAGE_ENABLED_VALIDATOR);
-            VALIDATORS.put(NETWORK_RECOMMENDATIONS_ENABLED,
-                    NETWORK_RECOMMENDATIONS_ENABLED_VALIDATOR);
-            VALIDATORS.put(WIFI_WAKEUP_ENABLED, WIFI_WAKEUP_ENABLED_VALIDATOR);
-            VALIDATORS.put(WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
-                    WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON_VALIDATOR);
-            VALIDATORS.put(USE_OPEN_WIFI_PACKAGE, USE_OPEN_WIFI_PACKAGE_VALIDATOR);
-            VALIDATORS.put(WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED,
-                    WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED_VALIDATOR);
-            VALIDATORS.put(EMERGENCY_TONE, EMERGENCY_TONE_VALIDATOR);
-            VALIDATORS.put(CALL_AUTO_RETRY, CALL_AUTO_RETRY_VALIDATOR);
-            VALIDATORS.put(DOCK_AUDIO_MEDIA_ENABLED, DOCK_AUDIO_MEDIA_ENABLED_VALIDATOR);
-            VALIDATORS.put(ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS,
-                    ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_VALIDATOR);
-            VALIDATORS.put(ENCODED_SURROUND_OUTPUT, ENCODED_SURROUND_OUTPUT_VALIDATOR);
-            VALIDATORS.put(ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS,
-                    ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS_VALIDATOR);
-            VALIDATORS.put(LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL,
-                    LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL_VALIDATOR);
-            VALIDATORS.put(LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED,
-                    LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED_VALIDATOR);
-            VALIDATORS.put(LOW_POWER_MODE_TRIGGER_LEVEL, LOW_POWER_MODE_TRIGGER_LEVEL_VALIDATOR);
-            VALIDATORS.put(LOW_POWER_MODE_TRIGGER_LEVEL_MAX,
-                    LOW_POWER_MODE_TRIGGER_LEVEL_VALIDATOR);
-            VALIDATORS.put(AUTOMATIC_POWER_SAVE_MODE, AUTOMATIC_POWER_SAVE_MODE_VALIDATOR);
-            VALIDATORS.put(DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
-                    DYNAMIC_POWER_SAVINGS_VALIDATOR);
-            VALIDATORS.put(BLUETOOTH_ON, BLUETOOTH_ON_VALIDATOR);
-            VALIDATORS.put(PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_VALIDATOR);
-            VALIDATORS.put(PRIVATE_DNS_SPECIFIER, PRIVATE_DNS_SPECIFIER_VALIDATOR);
-            VALIDATORS.put(SOFT_AP_TIMEOUT_ENABLED, SOFT_AP_TIMEOUT_ENABLED_VALIDATOR);
-            VALIDATORS.put(WIFI_SCAN_THROTTLE_ENABLED, WIFI_SCAN_THROTTLE_ENABLED_VALIDATOR);
-            VALIDATORS.put(APP_AUTO_RESTRICTION_ENABLED, APP_AUTO_RESTRICTION_ENABLED_VALIDATOR);
-            VALIDATORS.put(ZEN_DURATION, ZEN_DURATION_VALIDATOR);
-            VALIDATORS.put(CHARGING_VIBRATION_ENABLED, CHARGING_VIBRATION_ENABLED_VALIDATOR);
-            VALIDATORS.put(DEVICE_PROVISIONING_MOBILE_DATA_ENABLED, BOOLEAN_VALIDATOR);
-            VALIDATORS.put(REQUIRE_PASSWORD_TO_DECRYPT, BOOLEAN_VALIDATOR);
-            VALIDATORS.put(DEVICE_DEMO_MODE, BOOLEAN_VALIDATOR);
-            VALIDATORS.put(WIFI_PNO_FREQUENCY_CULLING_ENABLED,
-                    WIFI_PNO_FREQUENCY_CULLING_ENABLED_VALIDATOR);
-            VALIDATORS.put(WIFI_PNO_RECENCY_SORTING_ENABLED,
-                    WIFI_PNO_RECENCY_SORTING_ENABLED_VALIDATOR);
-            VALIDATORS.put(WIFI_LINK_PROBING_ENABLED, WIFI_LINK_PROBING_ENABLED_VALIDATOR);
-            VALIDATORS.put(AWARE_ALLOWED, AWARE_ALLOWED_VALIDATOR);
-            VALIDATORS.put(POWER_BUTTON_LONG_PRESS, POWER_BUTTON_LONG_PRESS_VALIDATOR);
-            VALIDATORS.put(POWER_BUTTON_VERY_LONG_PRESS, POWER_BUTTON_VERY_LONG_PRESS_VALIDATOR);
-        }
 
         /**
          * Global settings that shouldn't be persisted.
diff --git a/core/java/android/provider/TEST_MAPPING b/core/java/android/provider/TEST_MAPPING
index 52a6a45..773be80 100644
--- a/core/java/android/provider/TEST_MAPPING
+++ b/core/java/android/provider/TEST_MAPPING
@@ -7,6 +7,14 @@
                     "include-annotation": "android.platform.test.annotations.Presubmit"
                 }
             ]
+        },
+        {
+            "name": "SettingsProviderTest",
+            "options": [
+                {
+                    "include-annotation": "android.platform.test.annotations.Presubmit"
+                }
+            ]
         }
     ]
 }
diff --git a/core/java/android/service/autofill/augmented/FillRequest.java b/core/java/android/service/autofill/augmented/FillRequest.java
index 9a97bb2..0b44470 100644
--- a/core/java/android/service/autofill/augmented/FillRequest.java
+++ b/core/java/android/service/autofill/augmented/FillRequest.java
@@ -81,6 +81,7 @@
         return mProxy.getSmartSuggestionParams();
     }
 
+    @NonNull
     @Override
     public String toString() {
         return "FillRequest[act=" + getActivityComponent().flattenToShortString()
diff --git a/core/java/android/service/autofill/augmented/PresentationParams.java b/core/java/android/service/autofill/augmented/PresentationParams.java
index 334487d..8b3a001 100644
--- a/core/java/android/service/autofill/augmented/PresentationParams.java
+++ b/core/java/android/service/autofill/augmented/PresentationParams.java
@@ -82,6 +82,7 @@
             return mBounds;
         }
 
+        @NonNull
         @Override
         public String toString() {
             return mBounds.toString();
diff --git a/core/java/android/service/contentcapture/ActivityEvent.java b/core/java/android/service/contentcapture/ActivityEvent.java
index fc781c2..b741cff 100644
--- a/core/java/android/service/contentcapture/ActivityEvent.java
+++ b/core/java/android/service/contentcapture/ActivityEvent.java
@@ -111,6 +111,7 @@
         }
     }
 
+    @NonNull
     @Override
     public String toString() {
         return new StringBuilder("ActivityEvent[").append(mComponentName.toShortString())
diff --git a/core/java/android/service/euicc/EuiccProfileInfo.java b/core/java/android/service/euicc/EuiccProfileInfo.java
index 702837b..6c357cc 100644
--- a/core/java/android/service/euicc/EuiccProfileInfo.java
+++ b/core/java/android/service/euicc/EuiccProfileInfo.java
@@ -16,6 +16,7 @@
 package android.service.euicc;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
@@ -395,7 +396,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (this == obj) {
             return true;
         }
@@ -430,6 +431,7 @@
         return result;
     }
 
+    @NonNull
     @Override
     public String toString() {
         return "EuiccProfileInfo (nickname="
diff --git a/core/java/android/service/notification/Adjustment.java b/core/java/android/service/notification/Adjustment.java
index aa114450..8ab687f 100644
--- a/core/java/android/service/notification/Adjustment.java
+++ b/core/java/android/service/notification/Adjustment.java
@@ -257,6 +257,7 @@
         dest.writeString(mIssuer);
     }
 
+    @NonNull
     @Override
     public String toString() {
         return "Adjustment{"
diff --git a/core/java/android/service/notification/NotificationStats.java b/core/java/android/service/notification/NotificationStats.java
index 2b4c24c..8be114c 100644
--- a/core/java/android/service/notification/NotificationStats.java
+++ b/core/java/android/service/notification/NotificationStats.java
@@ -16,6 +16,8 @@
 package android.service.notification;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.app.RemoteInput;
@@ -266,7 +268,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
 
@@ -293,6 +295,7 @@
         return result;
     }
 
+    @NonNull
     @Override
     public String toString() {
         final StringBuilder sb = new StringBuilder("NotificationStats{");
diff --git a/core/java/android/service/notification/SnoozeCriterion.java b/core/java/android/service/notification/SnoozeCriterion.java
index 938cc10..eb624c9 100644
--- a/core/java/android/service/notification/SnoozeCriterion.java
+++ b/core/java/android/service/notification/SnoozeCriterion.java
@@ -15,6 +15,7 @@
  */
 package android.service.notification;
 
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.os.Parcel;
@@ -118,7 +119,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
 
diff --git a/core/java/android/service/resolver/ResolverTarget.java b/core/java/android/service/resolver/ResolverTarget.java
index 33b3283..b3657c4 100644
--- a/core/java/android/service/resolver/ResolverTarget.java
+++ b/core/java/android/service/resolver/ResolverTarget.java
@@ -16,13 +16,10 @@
 
 package android.service.resolver;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
-import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.util.ArrayMap;
-
-import java.util.Map;
 
 /**
  * A ResolverTarget contains features by which an app or option will be ranked, in
@@ -173,6 +170,7 @@
     }
 
     // serialize the class to a string.
+    @NonNull
     @Override
     public String toString() {
         return "ResolverTarget{"
diff --git a/core/java/android/service/watchdog/ExplicitHealthCheckService.java b/core/java/android/service/watchdog/ExplicitHealthCheckService.java
index dc9c858..619c507 100644
--- a/core/java/android/service/watchdog/ExplicitHealthCheckService.java
+++ b/core/java/android/service/watchdog/ExplicitHealthCheckService.java
@@ -229,13 +229,14 @@
             return mHealthCheckTimeoutMillis;
         }
 
+        @NonNull
         @Override
         public String toString() {
             return "PackageConfig{" + mPackageName + ", " + mHealthCheckTimeoutMillis + "}";
         }
 
         @Override
-        public boolean equals(Object other) {
+        public boolean equals(@Nullable Object other) {
             if (other == this) {
                 return true;
             }
diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java
index bab4bc36..3b6ec0b 100644
--- a/core/java/android/text/format/Time.java
+++ b/core/java/android/text/format/Time.java
@@ -937,9 +937,12 @@
     }
 
     /**
-     * Returns true if the day of the given time is the epoch on the Julian Calendar
-     * (January 1, 1970 on the Gregorian calendar).
-     *
+     * Returns true if the instant of the supplied time would be for the
+     * Gregorian calendar date January 1, 1970 <em>for a user observing UTC
+     * </em>, i.e. the timezone of the time object is ignored.
+     * <p>
+     * See {@link #getJulianDay(long, long)} for how to determine the Julian day
+     * for the timezone of the time object.
      * <p>
      * This method can return an incorrect answer when the date / time fields have
      * been set to a local time that contradicts the available timezone information.
@@ -949,31 +952,39 @@
      */
     public static boolean isEpoch(Time time) {
         long millis = time.toMillis(true);
-        return getJulianDay(millis, 0) == EPOCH_JULIAN_DAY;
+        return getJulianDay(millis, 0 /* UTC offset */) == EPOCH_JULIAN_DAY;
     }
 
     /**
      * Computes the Julian day number for a point in time in a particular
-     * timezone. The Julian day for a given date is the same for every
-     * timezone. For example, the Julian day for July 1, 2008 is 2454649.
+     * timezone. The Julian day for a given calendar date is the same for
+     * every timezone. For example, the Julian day for July 1, 2008 is
+     * 2454649.
      *
      * <p>Callers must pass the time in UTC millisecond (as can be returned
      * by {@link #toMillis(boolean)} or {@link #normalize(boolean)})
-     * and the offset from UTC of the timezone in seconds (as might be in
-     * {@link #gmtoff}).
+     * and the offset from UTC of the timezone in seconds at that time (as
+     * might be in {@link #gmtoff}).
      *
      * <p>The Julian day is useful for testing if two events occur on the
      * same calendar date and for determining the relative time of an event
      * from the present ("yesterday", "3 days ago", etc.).
      *
      * @param millis the time in UTC milliseconds
-     * @param gmtoff the offset from UTC in seconds
+     * @param gmtoffSeconds the offset from UTC in seconds
      * @return the Julian day
+     * @deprecated Use {@link java.time.temporal.JulianFields#JULIAN_DAY} instead.
      */
-    public static int getJulianDay(long millis, long gmtoff) {
-        long offsetMillis = gmtoff * 1000;
-        long julianDay = (millis + offsetMillis) / DateUtils.DAY_IN_MILLIS;
-        return (int) julianDay + EPOCH_JULIAN_DAY;
+    @Deprecated
+    public static int getJulianDay(long millis, long gmtoffSeconds) {
+        long offsetMillis = gmtoffSeconds * 1000;
+        long adjustedMillis = millis + offsetMillis;
+        long julianDay = adjustedMillis / DateUtils.DAY_IN_MILLIS;
+        // Negative adjustedMillis values must round towards Integer.MIN_VALUE.
+        if (adjustedMillis < 0 && adjustedMillis % DateUtils.DAY_IN_MILLIS != 0) {
+            julianDay--;
+        }
+        return (int) (julianDay + EPOCH_JULIAN_DAY);
     }
 
     /**
diff --git a/core/java/android/view/GestureExclusionTracker.java b/core/java/android/view/GestureExclusionTracker.java
index 6fcdd71..fcc14c1 100644
--- a/core/java/android/view/GestureExclusionTracker.java
+++ b/core/java/android/view/GestureExclusionTracker.java
@@ -44,7 +44,7 @@
         while (i.hasNext()) {
             final GestureExclusionViewInfo info = i.next();
             final View v = info.getView();
-            if (v == null || !v.isAttachedToWindow()) {
+            if (v == null || !v.isAttachedToWindow() || !v.isShown()) {
                 mGestureExclusionViewsChanged = true;
                 i.remove();
                 continue;
@@ -122,7 +122,8 @@
 
         public int update() {
             final View excludedView = getView();
-            if (excludedView == null || !excludedView.isAttachedToWindow()) return GONE;
+            if (excludedView == null || !excludedView.isAttachedToWindow()
+                    || !excludedView.isShown()) return GONE;
             final List<Rect> localRects = excludedView.getSystemGestureExclusionRects();
             final List<Rect> newRects = new ArrayList<>(localRects.size());
             for (Rect src : localRects) {
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
index 83abf1a..3bf44ac 100644
--- a/core/java/android/view/ImeInsetsSourceConsumer.java
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -42,7 +42,6 @@
      * editor {@link #mFocusedEditor} if {@link #isServedEditorRendered} is {@code true}.
      */
     private boolean mShowOnNextImeRender;
-    private boolean mHasWindowFocus;
 
     public ImeInsetsSourceConsumer(
             InsetsState state, Supplier<Transaction> transactionSupplier,
@@ -68,23 +67,18 @@
     }
 
     public void applyImeVisibility(boolean setVisible) {
-        if (!mHasWindowFocus) {
-            // App window doesn't have focus, any visibility changes would be no-op.
-            return;
-        }
-
         mController.applyImeVisibility(setVisible);
     }
 
     @Override
     public void onWindowFocusGained() {
-        mHasWindowFocus = true;
+        super.onWindowFocusGained();
         getImm().registerImeConsumer(this);
     }
 
     @Override
     public void onWindowFocusLost() {
-        mHasWindowFocus = false;
+        super.onWindowFocusLost();
         getImm().unregisterImeConsumer(this);
     }
 
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index bf16e3d..d0ecae9 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -296,7 +296,8 @@
         final ArraySet<Integer> internalTypes = mState.toInternalType(types);
         final SparseArray<InsetsSourceConsumer> consumers = new SparseArray<>();
 
-        Pair<Integer, Boolean> typesReadyPair = collectConsumers(fromIme, internalTypes, consumers);
+        Pair<Integer, Boolean> typesReadyPair = collectConsumers(
+                fromIme, internalTypes, consumers, listener);
         int typesReady = typesReadyPair.first;
         boolean isReady = typesReadyPair.second;
         if (!isReady) {
@@ -324,13 +325,16 @@
      * @return Pair of (types ready to animate, is ready to animate).
      */
     private Pair<Integer, Boolean> collectConsumers(boolean fromIme,
-            ArraySet<Integer> internalTypes, SparseArray<InsetsSourceConsumer> consumers) {
+            ArraySet<Integer> internalTypes, SparseArray<InsetsSourceConsumer> consumers,
+            WindowInsetsAnimationControlListener listener) {
         int typesReady = 0;
         boolean isReady = true;
         for (int i = internalTypes.size() - 1; i >= 0; i--) {
             InsetsSourceConsumer consumer = getSourceConsumer(internalTypes.valueAt(i));
-            if (consumer.getControl() != null) {
-                if (!consumer.isVisible()) {
+            // Double check for IME that IME target window has focus.
+            if (consumer.getType() != TYPE_IME || consumer.hasWindowFocus()) {
+                boolean setVisible = !consumer.isVisible();
+                if (setVisible) {
                     // Show request
                     switch(consumer.requestShow(fromIme)) {
                         case ShowResult.SHOW_IMMEDIATELY:
@@ -357,8 +361,11 @@
                 }
                 consumers.put(consumer.getType(), consumer);
             } else {
-                // TODO: Let calling app know it's not possible, or wait
-                // TODO: Remove it from types
+                // window doesnt have focus, no-op.
+                isReady = false;
+                // TODO: Let the calling app know that window has lost focus and
+                //       show()/hide()/controlWindowInsetsAnimation requests will be ignored.
+                typesReady &= ~InsetsState.toPublicType(consumer.getType());
             }
         }
         return new Pair<>(typesReady, isReady);
@@ -533,7 +540,10 @@
 
             @Override
             public void onCancelled() {
-                mAnimator.cancel();
+                // Animator can be null when it is cancelled before onReady() completes.
+                if (mAnimator != null) {
+                    mAnimator.cancel();
+                }
             }
 
             private void onAnimationFinish() {
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index a780158..9edccb3 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -58,6 +58,7 @@
     private final @InternalInsetType int mType;
     private final InsetsState mState;
     private @Nullable InsetsSourceControl mSourceControl;
+    private boolean mHasWindowFocus;
 
     public InsetsSourceConsumer(@InternalInsetType int type, InsetsState state,
             Supplier<Transaction> transactionSupplier, InsetsController controller) {
@@ -104,12 +105,20 @@
     /**
      * Called when current window gains focus
      */
-    public void onWindowFocusGained() {}
+    public void onWindowFocusGained() {
+        mHasWindowFocus = true;
+    }
 
     /**
      * Called when current window loses focus.
      */
-    public void onWindowFocusLost() {}
+    public void onWindowFocusLost() {
+        mHasWindowFocus = false;
+    }
+
+    boolean hasWindowFocus() {
+        return mHasWindowFocus;
+    }
 
     boolean applyLocalVisibilityOverride() {
 
@@ -153,7 +162,6 @@
             return;
         }
         mVisible = visible;
-        applyHiddenToControl();
         applyLocalVisibilityOverride();
         mController.notifyVisibilityChanged();
     }
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index b76f2a1..a04c39b 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
+import static android.view.ViewRootImpl.NEW_INSETS_MODE_IME;
 import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
 import static android.view.WindowInsets.Type.MANDATORY_SYSTEM_GESTURES;
 import static android.view.WindowInsets.Type.SIZE;
@@ -161,13 +162,15 @@
                 continue;
             }
 
+            boolean skipNonImeInImeMode = ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_IME
+                    && source.getType() != TYPE_IME;
             boolean skipSystemBars = ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_FULL
                     && (type == TYPE_TOP_BAR || type == TYPE_NAVIGATION_BAR);
             boolean skipIme = source.getType() == TYPE_IME
                     && (legacySoftInputMode & LayoutParams.SOFT_INPUT_ADJUST_RESIZE) == 0;
             boolean skipLegacyTypes = ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_NONE
                     && (toPublicType(type) & Type.compatSystemInsets()) != 0;
-            if (skipSystemBars || skipIme || skipLegacyTypes) {
+            if (skipSystemBars || skipIme || skipLegacyTypes || skipNonImeInImeMode) {
                 typeVisibilityMap[indexOf(toPublicType(type))] = source.isVisible();
                 continue;
             }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 1779a80..6ce7120 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -14403,6 +14403,7 @@
         }
 
         notifyAppearedOrDisappearedForContentCaptureIfNeeded(isVisible);
+        updateSystemGestureExclusionRects();
     }
 
     /**
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index d474b4d..61debc8 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -4745,8 +4745,8 @@
         /**
          * Obtains a pooled instance.
          *
-         * @param rowCount The number of rows.
-         * @param columnCount The number of columns.
+         * @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.
          */
         public static CollectionInfo obtain(int rowCount, int columnCount,
@@ -4800,7 +4800,7 @@
         /**
          * Gets the number of rows.
          *
-         * @return The row count.
+         * @return The row count, or -1 if count is unknown.
          */
         public int getRowCount() {
             return mRowCount;
@@ -4809,7 +4809,7 @@
         /**
          * Gets the number of columns.
          *
-         * @return The column count.
+         * @return The column count, or -1 if count is unknown.
          */
         public int getColumnCount() {
             return mColumnCount;
diff --git a/core/java/android/view/contentcapture/ContentCaptureEvent.java b/core/java/android/view/contentcapture/ContentCaptureEvent.java
index bd38629..c29d251 100644
--- a/core/java/android/view/contentcapture/ContentCaptureEvent.java
+++ b/core/java/android/view/contentcapture/ContentCaptureEvent.java
@@ -373,6 +373,7 @@
         }
     }
 
+    @NonNull
     @Override
     public String toString() {
         final StringBuilder string = new StringBuilder("ContentCaptureEvent[type=")
diff --git a/core/java/android/view/textclassifier/OWNERS b/core/java/android/view/textclassifier/OWNERS
new file mode 100644
index 0000000..893a083
--- /dev/null
+++ b/core/java/android/view/textclassifier/OWNERS
@@ -0,0 +1,10 @@
+# Bug component: 709498
+
+toki@google.com
+tonymak@google.com
+zilka@google.com
+jalt@google.com
+joannechung@google.com
+svetoslavganov@google.com
+eugeniom@google.com
+samsellem@google.com
\ No newline at end of file
diff --git a/core/java/android/view/textclassifier/TextClassificationSessionId.java b/core/java/android/view/textclassifier/TextClassificationSessionId.java
index 5e62a11..8b68e17 100644
--- a/core/java/android/view/textclassifier/TextClassificationSessionId.java
+++ b/core/java/android/view/textclassifier/TextClassificationSessionId.java
@@ -96,8 +96,6 @@
      * Flattens this id to a string.
      *
      * @return The flattened id.
-     *
-     * @hide
      */
     public @NonNull String flattenToString() {
         return mValue;
diff --git a/core/java/android/view/textclassifier/TextClassifierEvent.java b/core/java/android/view/textclassifier/TextClassifierEvent.java
index a041296..eb6aec0 100644
--- a/core/java/android/view/textclassifier/TextClassifierEvent.java
+++ b/core/java/android/view/textclassifier/TextClassifierEvent.java
@@ -86,11 +86,13 @@
             TYPE_ACTIONS_SHOWN, TYPE_LINK_CLICKED, TYPE_OVERTYPE, TYPE_COPY_ACTION,
             TYPE_PASTE_ACTION, TYPE_CUT_ACTION, TYPE_SHARE_ACTION, TYPE_SMART_ACTION,
             TYPE_SELECTION_DRAG, TYPE_SELECTION_DESTROYED, TYPE_OTHER_ACTION, TYPE_SELECT_ALL,
-            TYPE_SELECTION_RESET, TYPE_MANUAL_REPLY, TYPE_ACTIONS_GENERATED})
+            TYPE_SELECTION_RESET, TYPE_MANUAL_REPLY, TYPE_ACTIONS_GENERATED, TYPE_LINKS_GENERATED})
     public @interface Type {
         // For custom event types, use range 1,000,000+.
     }
 
+    // All these event type constants are required to match with those defined in
+    // textclassifier_enums.proto.
     /** User started a new selection. */
     public static final int TYPE_SELECTION_STARTED = 1;
     /** User modified an existing selection. */
@@ -131,6 +133,8 @@
     public static final int TYPE_MANUAL_REPLY = 19;
     /** TextClassifier generated some actions */
     public static final int TYPE_ACTIONS_GENERATED = 20;
+    /** Some text links were generated.*/
+    public static final int TYPE_LINKS_GENERATED = 21;
 
     @Category
     private final int mEventCategory;
@@ -365,7 +369,8 @@
         out.append(this.getClass().getSimpleName());
         out.append("{");
         out.append("mEventCategory=").append(mEventCategory);
-        out.append(", mEventTypes=").append(Arrays.toString(mEntityTypes));
+        out.append(", mEventType=").append(mEventType);
+        out.append(", mEntityTypes=").append(Arrays.toString(mEntityTypes));
         out.append(", mEventContext=").append(mEventContext);
         out.append(", mResultId=").append(mResultId);
         out.append(", mEventIndex=").append(mEventIndex);
@@ -373,11 +378,19 @@
         out.append(", mScores=").append(Arrays.toString(mScores));
         out.append(", mModelName=").append(mModelName);
         out.append(", mActionIndices=").append(Arrays.toString(mActionIndices));
+        toString(out);
         out.append("}");
         return out.toString();
     }
 
     /**
+     * Overrides this to append extra fields to the output of {@link #toString()}.
+     * <p>
+     * Extra fields should be  formatted like this: ", {field_name}={field_value}".
+     */
+    void toString(StringBuilder out) {}
+
+    /**
      * Returns a {@link SelectionEvent} equivalent of this event; or {@code null} if it can not be
      * converted to a {@link SelectionEvent}.
      * @hide
@@ -811,6 +824,16 @@
             return mRelativeSuggestedWordEndIndex;
         }
 
+        @Override
+        void toString(StringBuilder out) {
+            out.append(", getRelativeWordStartIndex=").append(mRelativeWordStartIndex);
+            out.append(", getRelativeWordEndIndex=").append(mRelativeWordEndIndex);
+            out.append(", getRelativeSuggestedWordStartIndex=")
+                    .append(mRelativeSuggestedWordStartIndex);
+            out.append(", getRelativeSuggestedWordEndIndex=")
+                    .append(mRelativeSuggestedWordEndIndex);
+        }
+
         /**
          * Builder class for {@link TextSelectionEvent}.
          */
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index e4b5eaa..2af7ac7 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1843,8 +1843,8 @@
 
     /**
      * Injects the supplied Java object into this WebView. The object is
-     * injected into the JavaScript context of the main frame, using the
-     * supplied name. This allows the Java object's methods to be
+     * injected into all frames of the web page, including all the iframes,
+     * using the supplied name. This allows the Java object's methods to be
      * accessed from JavaScript. For applications targeted to API
      * level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}
      * and above, only public methods that are annotated with
@@ -1883,6 +1883,11 @@
      * thread of this WebView. Care is therefore required to maintain thread
      * safety.
      * </li>
+     * <li> Because the object is exposed to all the frames, any frame could
+     * obtain the object name and call methods on it. There is no way to tell the
+     * calling frame's origin from the app side, so the app must not assume that
+     * the caller is trustworthy unless the app can guarantee that no third party
+     * content is ever loaded into the WebView even inside an iframe.</li>
      * <li> The Java object's fields are not accessible.</li>
      * <li> For applications targeted to API level {@link android.os.Build.VERSION_CODES#LOLLIPOP}
      * and above, methods of injected Java objects are enumerable from
@@ -2807,7 +2812,7 @@
     }
 
     @Override
-    public void onProvideContentCaptureStructure(ViewStructure structure, int flags) {
+    public void onProvideContentCaptureStructure(@NonNull ViewStructure structure, int flags) {
         mProvider.getViewDelegate().onProvideContentCaptureStructure(structure, flags);
     }
 
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index 5b129f4..1de2e72 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -20,7 +20,6 @@
 import android.app.ActivityManager;
 import android.app.ActivityThread;
 import android.app.ApplicationErrorReport;
-import android.content.type.MimeMapImpl;
 import android.os.Build;
 import android.os.DeadObjectException;
 import android.os.Debug;
@@ -34,9 +33,6 @@
 import com.android.server.NetworkManagementSocketTagger;
 import dalvik.system.RuntimeHooks;
 import dalvik.system.VMRuntime;
-
-import libcore.net.MimeMap;
-
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
@@ -214,14 +210,6 @@
         RuntimeHooks.setTimeZoneIdSupplier(() -> SystemProperties.get("persist.sys.timezone"));
 
         /*
-         * Replace libcore's minimal default mapping between MIME types and file
-         * extensions with a mapping that's suitable for Android. Android's mapping
-         * contains many more entries that are derived from IANA registrations but
-         * with several customizations (extensions, overrides).
-         */
-        MimeMap.setDefault(MimeMapImpl.createDefaultInstance());
-
-        /*
          * Sets handler for java.util.logging to use Android log facilities.
          * The odd "new instance-and-then-throw-away" is a mirror of how
          * the "java.util.logging.config.class" system property works. We
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 9ea9b06..b5d4945 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -92,11 +92,6 @@
     private static final int LOG_BOOT_PROGRESS_PRELOAD_START = 3020;
     private static final int LOG_BOOT_PROGRESS_PRELOAD_END = 3030;
 
-    /**
-     * when preloading, GC after allocating this many bytes
-     */
-    private static final int PRELOAD_GC_THRESHOLD = 50000;
-
     private static final String ABI_LIST_ARG = "--abi-list=";
 
     // TODO (chriswailes): Re-name this --zygote-socket-name= and then add a
@@ -281,11 +276,6 @@
             droppedPriviliges = true;
         }
 
-        // Alter the target heap utilization.  With explicit GCs this
-        // is not likely to have any effect.
-        float defaultUtilization = runtime.getTargetHeapUtilization();
-        runtime.setTargetHeapUtilization(0.8f);
-
         try {
             BufferedReader br =
                     new BufferedReader(new InputStreamReader(is), Zygote.SOCKET_BUFFER_SIZE);
@@ -301,9 +291,6 @@
 
                 Trace.traceBegin(Trace.TRACE_TAG_DALVIK, line);
                 try {
-                    if (false) {
-                        Log.v(TAG, "Preloading " + line + "...");
-                    }
                     // Load and explicitly initialize the given class. Use
                     // Class.forName(String, boolean, ClassLoader) to avoid repeated stack lookups
                     // (to derive the caller's class-loader). Use true to force initialization, and
@@ -334,8 +321,6 @@
             Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
         } finally {
             IoUtils.closeQuietly(is);
-            // Restore default.
-            runtime.setTargetHeapUtilization(defaultUtilization);
 
             // Fill in dex caches with classes, fields, and methods brought in by preloading.
             Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadDexCaches");
diff --git a/core/java/com/android/internal/widget/LockSettingsInternal.java b/core/java/com/android/internal/widget/LockSettingsInternal.java
index d459bfb..aab2f4b 100644
--- a/core/java/com/android/internal/widget/LockSettingsInternal.java
+++ b/core/java/com/android/internal/widget/LockSettingsInternal.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.widget;
 
+import android.annotation.Nullable;
+import android.app.admin.PasswordMetrics;
 
 /**
  * LockSettingsService local system service interface.
@@ -61,4 +63,18 @@
             long tokenHandle, byte[] token, int requestedQuality, int userId);
 
     public abstract boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId);
+
+    /**
+     * Returns PasswordMetrics object corresponding to the given user's lockscreen password.
+     * If the user has a password but its metrics isn't known yet (for example if the device
+     * has not been unlocked since boot), this method will return {@code null}.
+     * If the user has no password, a default PasswordMetrics (PASSWORD_QUALITY_UNSPECIFIED)
+     * will be returned.
+     *
+     * Calling this method on a managed profile user with unified challenge is undefined.
+     *
+     * @param userHandle the user for whom to provide metrics.
+     * @return the user password metrics.
+     */
+    public abstract @Nullable PasswordMetrics getUserPasswordMetrics(int userHandle);
 }
diff --git a/core/java/com/package.html b/core/java/com/package.html
new file mode 100644
index 0000000..8f35da9
--- /dev/null
+++ b/core/java/com/package.html
@@ -0,0 +1,8 @@
+<!--
+  This file is to hide classes in com.* packages from SDK
+-->
+<html>
+<body>
+    {@hide}
+</body>
+</html>
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 2987c5e..11d321f 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -220,10 +220,10 @@
 {
     ALOG_ASSERT(env->IsInstanceOf(obj, gRect_class));
 
-    ir->set(env->GetIntField(obj, gRect_leftFieldID),
-            env->GetIntField(obj, gRect_topFieldID),
-            env->GetIntField(obj, gRect_rightFieldID),
-            env->GetIntField(obj, gRect_bottomFieldID));
+    ir->setLTRB(env->GetIntField(obj, gRect_leftFieldID),
+                env->GetIntField(obj, gRect_topFieldID),
+                env->GetIntField(obj, gRect_rightFieldID),
+                env->GetIntField(obj, gRect_bottomFieldID));
     return ir;
 }
 
@@ -241,10 +241,10 @@
 {
     ALOG_ASSERT(env->IsInstanceOf(obj, gRectF_class));
 
-    r->set(env->GetFloatField(obj, gRectF_leftFieldID),
-           env->GetFloatField(obj, gRectF_topFieldID),
-           env->GetFloatField(obj, gRectF_rightFieldID),
-           env->GetFloatField(obj, gRectF_bottomFieldID));
+    r->setLTRB(env->GetFloatField(obj, gRectF_leftFieldID),
+               env->GetFloatField(obj, gRectF_topFieldID),
+               env->GetFloatField(obj, gRectF_rightFieldID),
+               env->GetFloatField(obj, gRectF_bottomFieldID));
     return r;
 }
 
@@ -252,10 +252,10 @@
 {
     ALOG_ASSERT(env->IsInstanceOf(obj, gRect_class));
 
-    r->set(SkIntToScalar(env->GetIntField(obj, gRect_leftFieldID)),
-           SkIntToScalar(env->GetIntField(obj, gRect_topFieldID)),
-           SkIntToScalar(env->GetIntField(obj, gRect_rightFieldID)),
-           SkIntToScalar(env->GetIntField(obj, gRect_bottomFieldID)));
+    r->setLTRB(SkIntToScalar(env->GetIntField(obj, gRect_leftFieldID)),
+               SkIntToScalar(env->GetIntField(obj, gRect_topFieldID)),
+               SkIntToScalar(env->GetIntField(obj, gRect_rightFieldID)),
+               SkIntToScalar(env->GetIntField(obj, gRect_bottomFieldID)));
     return r;
 }
 
diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp
index 1fb5fe3..87662f7 100644
--- a/core/jni/android/graphics/Region.cpp
+++ b/core/jni/android/graphics/Region.cpp
@@ -61,7 +61,7 @@
 
 static jboolean Region_setRect(JNIEnv* env, jobject, jlong dstHandle, jint left, jint top, jint right, jint bottom) {
     SkRegion* dst = reinterpret_cast<SkRegion*>(dstHandle);
-    bool result = dst->setRect(left, top, right, bottom);
+    bool result = dst->setRect({left, top, right, bottom});
     return boolTojboolean(result);
 }
 
@@ -92,10 +92,7 @@
 
 static jboolean Region_op0(JNIEnv* env, jobject, jlong dstHandle, jint left, jint top, jint right, jint bottom, jint op) {
     SkRegion* dst = reinterpret_cast<SkRegion*>(dstHandle);
-    SkIRect ir;
-
-    ir.set(left, top, right, bottom);
-    bool result = dst->op(ir, (SkRegion::Op)op);
+    bool result = dst->op({left, top, right, bottom}, (SkRegion::Op)op);
     return boolTojboolean(result);
 }
 
@@ -139,13 +136,13 @@
 }
 
 static jboolean Region_quickContains(JNIEnv* env, jobject region, jint left, jint top, jint right, jint bottom) {
-    bool result = GetSkRegion(env, region)->quickContains(left, top, right, bottom);
+    bool result = GetSkRegion(env, region)->quickContains({left, top, right, bottom});
     return boolTojboolean(result);
 }
 
 static jboolean Region_quickRejectIIII(JNIEnv* env, jobject region, jint left, jint top, jint right, jint bottom) {
     SkIRect ir;
-    ir.set(left, top, right, bottom);
+    ir.setLTRB(left, top, right, bottom);
     bool result = GetSkRegion(env, region)->quickReject(ir);
     return boolTojboolean(result);
 }
@@ -224,7 +221,7 @@
 
     SkRegion* region = new SkRegion;
     for (size_t x = 0; x + 4 <= rects.size(); x += 4) {
-        region->op(rects[x], rects[x+1], rects[x+2], rects[x+3], SkRegion::kUnion_Op);
+        region->op({rects[x], rects[x+1], rects[x+2], rects[x+3]}, SkRegion::kUnion_Op);
     }
 
     return reinterpret_cast<jlong>(region);
diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp
index 64caf33..2265268 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.cpp
+++ b/core/jni/android_hardware_input_InputWindowHandle.cpp
@@ -29,6 +29,7 @@
 #include "android_hardware_input_InputWindowHandle.h"
 #include "android_hardware_input_InputApplicationHandle.h"
 #include "android_util_Binder.h"
+#include <binder/IPCThreadState.h>
 
 namespace android {
 
@@ -80,6 +81,12 @@
 NativeInputWindowHandle::~NativeInputWindowHandle() {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     env->DeleteWeakGlobalRef(mObjWeak);
+
+    // Clear the weak reference to the layer handle and flush any binder ref count operations so we
+    // do not hold on to any binder references.
+    // TODO(b/139697085) remove this after it can be flushed automatically
+    mInfo.touchableRegionCropHandle.clear();
+    IPCThreadState::self()->flushCommands();
 }
 
 jobject NativeInputWindowHandle::getInputWindowHandleObjLocalRef(JNIEnv* env) {
diff --git a/core/proto/android/stats/textclassifier/textclassifier_enums.proto b/core/proto/android/stats/textclassifier/textclassifier_enums.proto
index 1885f19..4be7b7c 100644
--- a/core/proto/android/stats/textclassifier/textclassifier_enums.proto
+++ b/core/proto/android/stats/textclassifier/textclassifier_enums.proto
@@ -60,6 +60,8 @@
     MANUAL_REPLY = 19;
     // TextClassifier generated some actions
     ACTIONS_GENERATED = 20;
+    // Some text links were generated
+    LINKS_GENERATED = 21;
 }
 
 enum WidgetType {
diff --git a/core/res/TEST_MAPPING b/core/res/TEST_MAPPING
index 1d22d782..ccd91a4 100644
--- a/core/res/TEST_MAPPING
+++ b/core/res/TEST_MAPPING
@@ -4,7 +4,7 @@
             "name": "CtsPermission2TestCases",
             "options": [
                 {
-                    "include-filter": "android.permission2.cts.PermissionPolicyTest#testPlatformPermissionPolicyUnaltered"
+                    "include-filter": "android.permission2.cts.PermissionPolicyTest#platformPermissionPolicyIsUnaltered"
                 }
             ]
         }
diff --git a/core/res/res/values-mcc450-mnc08/config.xml b/core/res/res/values-mcc450-mnc08/config.xml
index ca26ec1..5edbaed 100644
--- a/core/res/res/values-mcc450-mnc08/config.xml
+++ b/core/res/res/values-mcc450-mnc08/config.xml
@@ -28,4 +28,14 @@
     <!-- Do not set the system language as value of EF LI/EF PL -->
     <bool name="config_use_sim_language_file">false</bool>
 
+    <!-- Configures encoding type to parse the User Data of an SMS for reserved TP-DCS value.
+         Refer to SmsConstants.java
+         ENCODING_UNKNOWN = 0;
+         ENCODING_7BIT = 1;
+         ENCODING_8BIT = 2;
+         ENCODING_16BIT = 3;
+         ENCODING_KSC5601 = 4;
+         -->
+    <integer name="default_reserved_data_coding_scheme">4</integer>
+
 </resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 0a60d71..2cd39cb 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3038,6 +3038,16 @@
         string that's stored in 8-bit unpacked format) characters.-->
     <bool translatable="false" name="config_sms_decode_gsm_8bit_data">false</bool>
 
+    <!-- Configures encoding type to parse the User Data of an SMS for reserved TP-DCS value.
+         Refer to SmsConstants.java
+         ENCODING_UNKNOWN = 0;
+         ENCODING_7BIT = 1;
+         ENCODING_8BIT = 2;
+         ENCODING_16BIT = 3;
+         ENCODING_KSC5601 = 4;
+         -->
+    <integer name="default_reserved_data_coding_scheme">2</integer>
+
     <!-- If EMS is not supported, framework breaks down EMS into single segment SMS
          and adds page info " x/y". This config is used to set which carrier doesn't
          support EMS and whether page info should be added at the beginning or the end.
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 58fc585..eaebd91 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2657,6 +2657,7 @@
   <java-symbol type="attr" name="ambientShadowAlpha" />
   <java-symbol type="attr" name="spotShadowAlpha" />
   <java-symbol type="bool" name="config_sms_decode_gsm_8bit_data" />
+  <java-symbol type="integer" name="default_reserved_data_coding_scheme" />
   <java-symbol type="dimen" name="text_size_small_material" />
   <java-symbol type="attr" name="checkMarkGravity" />
   <java-symbol type="layout" name="select_dialog_singlechoice_material" />
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 9955c51..2417209 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1270,10 +1270,8 @@
                 <action android:name="com.android.frameworks.coretests.activity.BROADCAST_REMOTE_DENIED" />
             </intent-filter>
         </receiver>
-        <service android:name="android.app.activity.LocalService">
-            <intent-filter>
-                <action android:name="com.android.frameworks.coretests.activity.SERVICE_LOCAL" />
-            </intent-filter>
+        <service android:name="android.app.activity.ServiceTest$RemoteService"
+                android:process=":RemoteService">
             <meta-data android:name="com.android.frameworks.coretests.string" android:value="foo" />
             <meta-data android:name="com.android.frameworks.coretests.boolean" android:value="true" />
             <meta-data android:name="com.android.frameworks.coretests.integer" android:value="100" />
@@ -1281,18 +1279,6 @@
             <meta-data android:name="com.android.frameworks.coretests.float" android:value="100.1" />
             <meta-data android:name="com.android.frameworks.coretests.reference" android:resource="@xml/metadata" />
         </service>
-        <service android:name="android.app.activity.LocalDeniedService"
-                android:permission="com.android.frameworks.coretests.permission.TEST_DENIED">
-            <intent-filter>
-                <action android:name="com.android.frameworks.coretests.activity.SERVICE_LOCAL_DENIED" />
-            </intent-filter>
-        </service>
-        <service android:name="android.app.activity.LocalGrantedService"
-                android:permission="com.android.frameworks.coretests.permission.TEST_GRANTED">
-            <intent-filter>
-                <action android:name="com.android.frameworks.coretests.activity.SERVICE_LOCAL_GRANTED" />
-            </intent-filter>
-        </service>
 
         <service
             android:name="android.service.settings.suggestions.MockSuggestionService"
diff --git a/core/tests/coretests/src/android/app/activity/LocalDeniedService.java b/core/tests/coretests/src/android/app/activity/LocalDeniedService.java
deleted file mode 100644
index 3bdac22..0000000
--- a/core/tests/coretests/src/android/app/activity/LocalDeniedService.java
+++ /dev/null
@@ -1,22 +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.app.activity;
-
-public class LocalDeniedService extends LocalService
-{
-}
-
diff --git a/core/tests/coretests/src/android/app/activity/LocalGrantedService.java b/core/tests/coretests/src/android/app/activity/LocalGrantedService.java
deleted file mode 100644
index 7ab0fb4..0000000
--- a/core/tests/coretests/src/android/app/activity/LocalGrantedService.java
+++ /dev/null
@@ -1,22 +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.app.activity;
-
-public class LocalGrantedService extends LocalService
-{
-}
-
diff --git a/core/tests/coretests/src/android/app/activity/LocalReceiver.java b/core/tests/coretests/src/android/app/activity/LocalReceiver.java
index bfd543f..7f81339 100644
--- a/core/tests/coretests/src/android/app/activity/LocalReceiver.java
+++ b/core/tests/coretests/src/android/app/activity/LocalReceiver.java
@@ -23,9 +23,9 @@
 import android.content.IntentFilter;
 import android.content.ReceiverCallNotAllowedException;
 import android.content.ServiceConnection;
-import android.os.RemoteException;
 import android.os.IBinder;
 import android.os.Parcel;
+import android.os.RemoteException;
 
 public class LocalReceiver extends BroadcastReceiver {
     public LocalReceiver() {
@@ -52,7 +52,7 @@
                     public void onServiceDisconnected(ComponentName name) {
                     }
                 };
-                context.bindService(new Intent(context, LocalService.class), sc, 0);
+                context.bindService(new Intent(context, ServiceTest.RemoteService.class), sc, 0);
                 context.unbindService(sc);
             } catch (ReceiverCallNotAllowedException e) {
                 //resultString = "This is the correct behavior but not yet implemented";
diff --git a/core/tests/coretests/src/android/app/activity/LocalService.java b/core/tests/coretests/src/android/app/activity/LocalService.java
deleted file mode 100644
index c31ca4b..0000000
--- a/core/tests/coretests/src/android/app/activity/LocalService.java
+++ /dev/null
@@ -1,122 +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.app.activity;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.util.Log;
-
-public class LocalService extends Service {
-    private final IBinder mBinder = new Binder() {
-
-        @Override
-        protected boolean onTransact(int code, Parcel data, Parcel reply,
-                int flags) throws RemoteException {
-            if (code == ServiceTest.SET_REPORTER_CODE) {
-                data.enforceInterface(ServiceTest.SERVICE_LOCAL);
-                mReportObject = data.readStrongBinder();
-                return true;
-            } else {
-                return super.onTransact(code, data, reply, flags);
-            }
-        }
-        
-    };
-
-    private IBinder mReportObject;
-    private int mStartCount = 1;
-
-    public LocalService() {
-    }
-
-    @Override
-    public void onStart(Intent intent, int startId) {
-        //Log.i("LocalService", "onStart: " + intent);
-        if (intent.getExtras() != null) {
-            mReportObject = intent.getExtras().getIBinder(ServiceTest.REPORT_OBJ_NAME);
-            if (mReportObject != null) {
-                try {
-                    Parcel data = Parcel.obtain();
-                    data.writeInterfaceToken(ServiceTest.SERVICE_LOCAL);
-                    data.writeInt(mStartCount);
-                    mStartCount++;
-                    mReportObject.transact(
-                            ServiceTest.STARTED_CODE, data, null, 0);
-                    data.recycle();
-                } catch (RemoteException e) {
-                }
-            }
-        }
-    }
-
-    @Override
-    public void onDestroy() {
-        Log.i("LocalService", "onDestroy: mReportObject=" + mReportObject);
-        if (mReportObject != null) {
-            try {
-                Parcel data = Parcel.obtain();
-                data.writeInterfaceToken(ServiceTest.SERVICE_LOCAL);
-                mReportObject.transact(
-                        ServiceTest.DESTROYED_CODE, data, null, 0);
-                data.recycle();
-            } catch (RemoteException e) {
-            }
-        }
-    }
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        Log.i("LocalService", "onBind: " + intent);
-        return mBinder;
-    }
-    
-    @Override
-    public boolean onUnbind(Intent intent) {
-        Log.i("LocalService", "onUnbind: " + intent);
-        if (mReportObject != null) {
-            try {
-                Parcel data = Parcel.obtain();
-                data.writeInterfaceToken(ServiceTest.SERVICE_LOCAL);
-                mReportObject.transact(
-                        ServiceTest.UNBIND_CODE, data, null, 0);
-                data.recycle();
-            } catch (RemoteException e) {
-            }
-        }
-        return true;
-    }
-    
-    @Override
-    public void onRebind(Intent intent) {
-        Log.i("LocalService", "onUnbind: " + intent);
-        if (mReportObject != null) {
-            try {
-                Parcel data = Parcel.obtain();
-                data.writeInterfaceToken(ServiceTest.SERVICE_LOCAL);
-                mReportObject.transact(
-                        ServiceTest.REBIND_CODE, data, null, 0);
-                data.recycle();
-            } catch (RemoteException e) {
-            }
-        }
-    }
-}
diff --git a/core/tests/coretests/src/android/app/activity/MetaDataTest.java b/core/tests/coretests/src/android/app/activity/MetaDataTest.java
index cf27878..be6e276 100644
--- a/core/tests/coretests/src/android/app/activity/MetaDataTest.java
+++ b/core/tests/coretests/src/android/app/activity/MetaDataTest.java
@@ -125,7 +125,7 @@
 
     @SmallTest
     public void testServiceWithData() throws Exception {
-        ComponentName cn = new ComponentName(mContext, LocalService.class);
+        ComponentName cn = new ComponentName(mContext, ServiceTest.RemoteService.class);
         ServiceInfo si = mContext.getPackageManager().getServiceInfo(
                 cn, PackageManager.GET_META_DATA);
 
diff --git a/core/tests/coretests/src/android/app/activity/ServiceTest.java b/core/tests/coretests/src/android/app/activity/ServiceTest.java
index 9d2aebd..c89f37d 100644
--- a/core/tests/coretests/src/android/app/activity/ServiceTest.java
+++ b/core/tests/coretests/src/android/app/activity/ServiceTest.java
@@ -16,453 +16,250 @@
 
 package android.app.activity;
 
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNot.not;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningServiceInfo;
+import android.app.Service;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.os.Binder;
-import android.os.Bundle;
+import android.os.Handler;
 import android.os.IBinder;
 import android.os.Parcel;
+import android.os.Process;
 import android.os.RemoteException;
 
 import androidx.test.filters.MediumTest;
-import androidx.test.filters.Suppress;
 
-// These test binders purport to support an interface whose canonical
-// interface name is ServiceTest.SERVICE_LOCAL
-// Temporarily suppress, this test is causing unit test suite run to fail
-// TODO: remove this suppress
-@Suppress
-public class ServiceTest extends ActivityTestsBase {
+import junit.framework.TestCase;
 
-    public static final String SERVICE_LOCAL =
-            "com.android.frameworks.coretests.activity.SERVICE_LOCAL";
-    public static final String SERVICE_LOCAL_GRANTED =
-            "com.android.frameworks.coretests.activity.SERVICE_LOCAL_GRANTED";
-    public static final String SERVICE_LOCAL_DENIED =
-            "com.android.frameworks.coretests.activity.SERVICE_LOCAL_DENIED";
+import org.junit.Test;
 
-    public static final String REPORT_OBJ_NAME = "report";
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.function.Supplier;
 
-    public static final int STARTED_CODE = 1;
-    public static final int DESTROYED_CODE = 2;
-    public static final int SET_REPORTER_CODE = 3;
-    public static final int UNBIND_CODE = 4;
-    public static final int REBIND_CODE = 5;
+/**
+ * Test for verifying the behavior of {@link Service}.
+ * <p>
+ * Tests related to internal behavior are usually placed here, e.g. the restart delay may be
+ * different depending on the current amount of restarting services.
+ * <p>
+ * Build/Install/Run:
+ *  atest FrameworksCoreTests:ServiceTest
+ */
+@MediumTest
+public class ServiceTest extends TestCase {
+    private static final String ACTION_SERVICE_STARTED = RemoteService.class.getName() + "_STARTED";
+    private static final String EXTRA_START_CODE = "start_code";
+    private static final String EXTRA_PID = "pid";
 
-    public static final int STATE_START_1 = 0;
-    public static final int STATE_START_2 = 1;
-    public static final int STATE_UNBIND = 2;
-    public static final int STATE_DESTROY = 3;
-    public static final int STATE_REBIND = 4;
-    public static final int STATE_UNBIND_ONLY = 5;
-    public int mStartState;
+    private static final long TIMEOUT_SEC = 5;
+    private static final int NOT_STARTED = -1;
 
-    public IBinder mStartReceiver = new Binder() {
+    private final Context mContext = getInstrumentation().getContext();
+    private final Intent mServiceIntent = new Intent(mContext, RemoteService.class);
+    private TestConnection mCurrentConnection;
+
+    @Override
+    public void tearDown() {
+        mContext.stopService(mServiceIntent);
+        if (mCurrentConnection != null) {
+            mContext.unbindService(mCurrentConnection);
+            mCurrentConnection = null;
+        }
+    }
+
+    @Test
+    public void testRestart_stickyStartedService_restarted() {
+        testRestartStartedService(Service.START_STICKY, true /* shouldRestart */);
+    }
+
+    @Test
+    public void testRestart_redeliveryStartedService_restarted() {
+        testRestartStartedService(Service.START_FLAG_REDELIVERY, true /* shouldRestart */);
+    }
+
+    @Test
+    public void testRestart_notStickyStartedService_notRestarted() {
+        testRestartStartedService(Service.START_NOT_STICKY, false /* shouldRestart */);
+    }
+
+    private void testRestartStartedService(int startFlag, boolean shouldRestart) {
+        final int servicePid = startService(startFlag);
+        assertThat(servicePid, not(NOT_STARTED));
+
+        final int restartedServicePid = waitForServiceStarted(
+                () -> Process.killProcess(servicePid));
+        assertThat(restartedServicePid, shouldRestart ? not(NOT_STARTED) : is(NOT_STARTED));
+    }
+
+    @Test
+    public void testRestart_boundService_restarted() {
+        final int servicePid = bindService(Context.BIND_AUTO_CREATE);
+        assertThat(servicePid, not(NOT_STARTED));
+
+        Process.killProcess(servicePid);
+        // The service should be restarted and the connection will receive onServiceConnected again.
+        assertThat(mCurrentConnection.takePid(), not(NOT_STARTED));
+    }
+
+    @Test
+    public void testRestart_boundNotStickyStartedService_restarted() {
+        final ActivityManager am = mContext.getSystemService(ActivityManager.class);
+        final Supplier<RunningServiceInfo> serviceInfoGetter = () -> {
+            for (RunningServiceInfo rs : am.getRunningServices(Integer.MAX_VALUE)) {
+                if (mServiceIntent.getComponent().equals(rs.service)) {
+                    return rs;
+                }
+            }
+            return null;
+        };
+
+        final int servicePid = bindService(Context.BIND_AUTO_CREATE);
+        assertThat(servicePid, not(NOT_STARTED));
+        assertThat(startService(Service.START_NOT_STICKY), is(servicePid));
+
+        RunningServiceInfo info = serviceInfoGetter.get();
+        assertThat(info, notNullValue());
+        assertThat(info.started, is(true));
+
+        Process.killProcess(servicePid);
+        // The service will be restarted for connection but the started state should be gone.
+        final int restartedServicePid = mCurrentConnection.takePid();
+        assertThat(restartedServicePid, not(NOT_STARTED));
+
+        info = serviceInfoGetter.get();
+        assertThat(info, notNullValue());
+        assertThat(info.started, is(false));
+        assertThat(info.clientCount, is(1));
+    }
+
+    @Test
+    public void testRestart_notStickyStartedNoAutoCreateBoundService_notRestarted() {
+        final int servicePid = startService(Service.START_NOT_STICKY);
+        assertThat(servicePid, not(NOT_STARTED));
+        assertThat(bindService(0 /* flags */), is(servicePid));
+
+        Process.killProcess(servicePid);
+        assertThat(mCurrentConnection.takePid(), is(NOT_STARTED));
+    }
+
+    /** @return The pid of the started service. */
+    private int startService(int code) {
+        return waitForServiceStarted(
+                () -> mContext.startService(mServiceIntent.putExtra(EXTRA_START_CODE, code)));
+    }
+
+    /** @return The pid of the started service. */
+    private int waitForServiceStarted(Runnable serviceTrigger) {
+        final CompletableFuture<Integer> pidResult = new CompletableFuture<>();
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                pidResult.complete(intent.getIntExtra(EXTRA_PID, NOT_STARTED));
+                mContext.unregisterReceiver(this);
+            }
+        }, new IntentFilter(ACTION_SERVICE_STARTED));
+
+        serviceTrigger.run();
+        try {
+            return pidResult.get(TIMEOUT_SEC, TimeUnit.SECONDS);
+        } catch (ExecutionException | InterruptedException | TimeoutException ignored) {
+        }
+        return NOT_STARTED;
+    }
+
+    /** @return The pid of the bound service. */
+    private int bindService(int flags) {
+        mCurrentConnection = new TestConnection();
+        assertThat(mContext.bindService(mServiceIntent, mCurrentConnection, flags), is(true));
+        return mCurrentConnection.takePid();
+    }
+
+    private static class TestConnection implements ServiceConnection {
+        private CompletableFuture<Integer> mServicePid = new CompletableFuture<>();
+
+        /**
+         * @return The pid of the connected service. It is only valid once after
+         *         {@link #onServiceConnected} is called.
+         */
+        int takePid() {
+            try {
+                return mServicePid.get(TIMEOUT_SEC, TimeUnit.SECONDS);
+            } catch (ExecutionException | InterruptedException | TimeoutException ignored) {
+            } finally {
+                mServicePid = new CompletableFuture<>();
+            }
+            return NOT_STARTED;
+        }
+
         @Override
-        protected boolean onTransact(int code, Parcel data, Parcel reply,
-                int flags) throws RemoteException {
-            //Log.i("ServiceTest", "Received code " + code + " in state " + mStartState);
-            if (code == STARTED_CODE) {
-                data.enforceInterface(SERVICE_LOCAL);
-                int count = data.readInt();
-                if (mStartState == STATE_START_1) {
-                    if (count == 1) {
-                        finishGood();
-                    } else {
-                        finishBad("onStart() again on an object when it should have been the first time");
-                    }
-                } else if (mStartState == STATE_START_2) {
-                    if (count == 2) {
-                        finishGood();
-                    } else {
-                        finishBad("onStart() the first time on an object when it should have been the second time");
-                    }
-                } else {
-                    finishBad("onStart() was called when not expected (state="+mStartState+")");
-                }
-                return true;
-            } else if (code == DESTROYED_CODE) {
-                data.enforceInterface(SERVICE_LOCAL);
-                if (mStartState == STATE_DESTROY) {
-                    finishGood();
-                } else {
-                    finishBad("onDestroy() was called when not expected (state="+mStartState+")");
-                }
-                return true;
-            } else if (code == UNBIND_CODE) {
-                data.enforceInterface(SERVICE_LOCAL);
-                if (mStartState == STATE_UNBIND) {
-                    mStartState = STATE_DESTROY;
-                } else if (mStartState == STATE_UNBIND_ONLY) {
-                    finishGood();
-                } else {
-                    finishBad("onUnbind() was called when not expected (state="+mStartState+")");
-                }
-                return true;
-            } else if (code == REBIND_CODE) {
-                data.enforceInterface(SERVICE_LOCAL);
-                if (mStartState == STATE_REBIND) {
-                    finishGood();
-                } else {
-                    finishBad("onRebind() was called when not expected (state="+mStartState+")");
-                }
-                return true;
-            } else {
-                return super.onTransact(code, data, reply, flags);
-            }
-        }
-    };
-
-    public class EmptyConnection implements ServiceConnection {
         public void onServiceConnected(ComponentName name, IBinder service) {
-        }
-
-        public void onServiceDisconnected(ComponentName name) {
-        }
-    }
-
-    public class TestConnection implements ServiceConnection {
-        private final boolean mExpectDisconnect;
-        private final boolean mSetReporter;
-        private boolean mMonitor;
-        private int mCount;
-
-        public TestConnection(boolean expectDisconnect, boolean setReporter) {
-            mExpectDisconnect = expectDisconnect;
-            mSetReporter = setReporter;
-            mMonitor = !setReporter;
-        }
-
-        void setMonitor(boolean v) {
-            mMonitor = v;
-        }
-
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            if (mSetReporter) {
-                Parcel data = Parcel.obtain();
-                data.writeInterfaceToken(SERVICE_LOCAL);
-                data.writeStrongBinder(mStartReceiver);
-                try {
-                    service.transact(SET_REPORTER_CODE, data, null, 0);
-                } catch (RemoteException e) {
-                    finishBad("DeadObjectException when sending reporting object");
-                }
+            final Parcel data = Parcel.obtain();
+            final Parcel reply = Parcel.obtain();
+            data.writeInterfaceToken(RemoteService.DESCRIPTOR);
+            try {
+                service.transact(RemoteService.TRANSACTION_GET_PID, data, reply, 0 /* flags */);
+                reply.readException();
+                mServicePid.complete(reply.readInt());
+            } catch (RemoteException e) {
+                mServicePid.complete(NOT_STARTED);
+            } finally {
                 data.recycle();
-            }
-
-            if (mMonitor) {
-                mCount++;
-                if (mStartState == STATE_START_1) {
-                    if (mCount == 1) {
-                        finishGood();
-                    } else {
-                        finishBad("onServiceConnected() again on an object when it should have been the first time");
-                    }
-                } else if (mStartState == STATE_START_2) {
-                    if (mCount == 2) {
-                        finishGood();
-                    } else {
-                        finishBad("onServiceConnected() the first time on an object when it should have been the second time");
-                    }
-                } else {
-                    finishBad("onServiceConnected() called unexpectedly");
-                }
+                reply.recycle();
             }
         }
 
+        @Override
         public void onServiceDisconnected(ComponentName name) {
-            if (mMonitor) {
-                if (mStartState == STATE_DESTROY) {
-                    if (mExpectDisconnect) {
-                        finishGood();
-                    } else {
-                        finishBad("onServiceDisconnected() when it shouldn't have been");
+        }
+    }
+
+    public static class RemoteService extends Service {
+        static final String DESCRIPTOR = RemoteService.class.getName();
+        static final int TRANSACTION_GET_PID = Binder.FIRST_CALL_TRANSACTION;
+
+        @Override
+        public int onStartCommand(Intent intent, int flags, int startId) {
+            new Handler().post(() -> {
+                final Intent responseIntent = new Intent(ACTION_SERVICE_STARTED);
+                responseIntent.putExtra(EXTRA_PID, Process.myPid());
+                sendBroadcast(responseIntent);
+            });
+            if (intent != null && intent.hasExtra(EXTRA_START_CODE)) {
+                return intent.getIntExtra(EXTRA_START_CODE, Service.START_NOT_STICKY);
+            }
+            return super.onStartCommand(intent, flags, startId);
+        }
+
+        @Override
+        public IBinder onBind(Intent intent) {
+            return new Binder() {
+                @Override
+                protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+                        throws RemoteException {
+                    if (code == TRANSACTION_GET_PID) {
+                        data.enforceInterface(DESCRIPTOR);
+                        reply.writeNoException();
+                        reply.writeInt(Process.myPid());
+                        return true;
                     }
-                } else {
-                    finishBad("onServiceDisconnected() called unexpectedly");
+                    return super.onTransact(code, data, reply, flags);
                 }
-            }
-        }
-    }
-
-    void startExpectResult(Intent service) {
-        startExpectResult(service, new Bundle());
-    }
-
-    void startExpectResult(Intent service, Bundle bundle) {
-        bundle.putIBinder(REPORT_OBJ_NAME, mStartReceiver);
-        boolean success = false;
-        try {
-            //Log.i("foo", "STATE_START_1");
-            mStartState = STATE_START_1;
-            getContext().startService(new Intent(service).putExtras(bundle));
-            waitForResultOrThrow(5 * 1000, "service to start first time");
-            //Log.i("foo", "STATE_START_2");
-            mStartState = STATE_START_2;
-            getContext().startService(new Intent(service).putExtras(bundle));
-            waitForResultOrThrow(5 * 1000, "service to start second time");
-            success = true;
-        } finally {
-            if (!success) {
-                try {
-                    getContext().stopService(service);
-                } catch (Exception e) {
-                    // eat
-                }
-            }
-        }
-        //Log.i("foo", "STATE_DESTROY");
-        mStartState = STATE_DESTROY;
-        getContext().stopService(service);
-        waitForResultOrThrow(5 * 1000, "service to be destroyed");
-    }
-
-    void startExpectNoPermission(Intent service) {
-        try {
-            getContext().startService(service);
-            fail("Expected security exception when starting " + service);
-        } catch (SecurityException e) {
-            // expected
-        }
-    }
-
-    void bindExpectResult(Intent service) {
-        TestConnection conn = new TestConnection(true, false);
-        TestConnection conn2 = new TestConnection(false, false);
-        boolean success = false;
-        try {
-            // Expect to see the TestConnection connected.
-            mStartState = STATE_START_1;
-            getContext().bindService(service, conn, 0);
-            getContext().startService(service);
-            waitForResultOrThrow(5 * 1000, "existing connection to receive service");
-
-            // Expect to see the second TestConnection connected.
-            getContext().bindService(service, conn2, 0);
-            waitForResultOrThrow(5 * 1000, "new connection to receive service");
-
-            getContext().unbindService(conn2);
-            success = true;
-        } finally {
-            if (!success) {
-                try {
-                    getContext().stopService(service);
-                    getContext().unbindService(conn);
-                    getContext().unbindService(conn2);
-                } catch (Exception e) {
-                    // eat
-                }
-            }
-        }
-
-        // Expect to see the TestConnection disconnected.
-        mStartState = STATE_DESTROY;
-        getContext().stopService(service);
-        waitForResultOrThrow(5 * 1000, "existing connection to lose service");
-
-        getContext().unbindService(conn);
-
-        conn = new TestConnection(true, true);
-        success = false;
-        try {
-            // Expect to see the TestConnection connected.
-            conn.setMonitor(true);
-            mStartState = STATE_START_1;
-            getContext().bindService(service, conn, 0);
-            getContext().startService(service);
-            waitForResultOrThrow(5 * 1000, "existing connection to receive service");
-
-            success = true;
-        } finally {
-            if (!success) {
-                try {
-                    getContext().stopService(service);
-                    getContext().unbindService(conn);
-                } catch (Exception e) {
-                    // eat
-                }
-            }
-        }
-
-        // Expect to see the service unbind and then destroyed.
-        conn.setMonitor(false);
-        mStartState = STATE_UNBIND;
-        getContext().stopService(service);
-        waitForResultOrThrow(5 * 1000, "existing connection to lose service");
-
-        getContext().unbindService(conn);
-
-        conn = new TestConnection(true, true);
-        success = false;
-        try {
-            // Expect to see the TestConnection connected.
-            conn.setMonitor(true);
-            mStartState = STATE_START_1;
-            getContext().bindService(service, conn, 0);
-            getContext().startService(service);
-            waitForResultOrThrow(5 * 1000, "existing connection to receive service");
-
-            success = true;
-        } finally {
-            if (!success) {
-                try {
-                    getContext().stopService(service);
-                    getContext().unbindService(conn);
-                } catch (Exception e) {
-                    // eat
-                }
-            }
-        }
-
-        // Expect to see the service unbind but not destroyed.
-        conn.setMonitor(false);
-        mStartState = STATE_UNBIND_ONLY;
-        getContext().unbindService(conn);
-        waitForResultOrThrow(5 * 1000, "existing connection to unbind service");
-
-        // Expect to see the service rebound.
-        mStartState = STATE_REBIND;
-        getContext().bindService(service, conn, 0);
-        waitForResultOrThrow(5 * 1000, "existing connection to rebind service");
-
-        // Expect to see the service unbind and then destroyed.
-        mStartState = STATE_UNBIND;
-        getContext().stopService(service);
-        waitForResultOrThrow(5 * 1000, "existing connection to lose service");
-
-        getContext().unbindService(conn);
-    }
-
-    void bindAutoExpectResult(Intent service) {
-        TestConnection conn = new TestConnection(false, true);
-        boolean success = false;
-        try {
-            conn.setMonitor(true);
-            mStartState = STATE_START_1;
-            getContext().bindService(
-                    service, conn, Context.BIND_AUTO_CREATE);
-            waitForResultOrThrow(5 * 1000, "connection to start and receive service");
-            success = true;
-        } finally {
-            if (!success) {
-                try {
-                    getContext().unbindService(conn);
-                } catch (Exception e) {
-                    // eat
-                }
-            }
-        }
-        mStartState = STATE_UNBIND;
-        getContext().unbindService(conn);
-        waitForResultOrThrow(5 * 1000, "disconnecting from service");
-    }
-
-    void bindExpectNoPermission(Intent service) {
-        TestConnection conn = new TestConnection(false, false);
-        try {
-            getContext().bindService(service, conn, Context.BIND_AUTO_CREATE);
-            fail("Expected security exception when binding " + service);
-        } catch (SecurityException e) {
-            // expected
-        } finally {
-            getContext().unbindService(conn);
-        }
-    }
-
-
-    @MediumTest
-    public void testLocalStartClass() throws Exception {
-        startExpectResult(new Intent(getContext(), LocalService.class));
-    }
-
-    @MediumTest
-    public void testLocalStartAction() throws Exception {
-        startExpectResult(new Intent(SERVICE_LOCAL));
-    }
-
-    @MediumTest
-    public void testLocalBindClass() throws Exception {
-        bindExpectResult(new Intent(getContext(), LocalService.class));
-    }
-
-    @MediumTest
-    public void testLocalBindAction() throws Exception {
-        bindExpectResult(new Intent(SERVICE_LOCAL));
-    }
-
-    @MediumTest
-    public void testLocalBindAutoClass() throws Exception {
-        bindAutoExpectResult(new Intent(getContext(), LocalService.class));
-    }
-
-    @MediumTest
-    public void testLocalBindAutoAction() throws Exception {
-        bindAutoExpectResult(new Intent(SERVICE_LOCAL));
-    }
-
-    @MediumTest
-    public void testLocalStartClassPermissionGranted() throws Exception {
-        startExpectResult(new Intent(getContext(), LocalGrantedService.class));
-    }
-
-    @MediumTest
-    public void testLocalStartActionPermissionGranted() throws Exception {
-        startExpectResult(new Intent(SERVICE_LOCAL_GRANTED));
-    }
-
-    @MediumTest
-    public void testLocalBindClassPermissionGranted() throws Exception {
-        bindExpectResult(new Intent(getContext(), LocalGrantedService.class));
-    }
-
-    @MediumTest
-    public void testLocalBindActionPermissionGranted() throws Exception {
-        bindExpectResult(new Intent(SERVICE_LOCAL_GRANTED));
-    }
-
-    @MediumTest
-    public void testLocalBindAutoClassPermissionGranted() throws Exception {
-        bindAutoExpectResult(new Intent(getContext(), LocalGrantedService.class));
-    }
-
-    @MediumTest
-    public void testLocalBindAutoActionPermissionGranted() throws Exception {
-        bindAutoExpectResult(new Intent(SERVICE_LOCAL_GRANTED));
-    }
-
-    @MediumTest
-    public void testLocalStartClassPermissionDenied() throws Exception {
-        startExpectNoPermission(new Intent(getContext(), LocalDeniedService.class));
-    }
-
-    @MediumTest
-    public void testLocalStartActionPermissionDenied() throws Exception {
-        startExpectNoPermission(new Intent(SERVICE_LOCAL_DENIED));
-    }
-
-    @MediumTest
-    public void testLocalBindClassPermissionDenied() throws Exception {
-        bindExpectNoPermission(new Intent(getContext(), LocalDeniedService.class));
-    }
-
-    @MediumTest
-    public void testLocalBindActionPermissionDenied() throws Exception {
-        bindExpectNoPermission(new Intent(SERVICE_LOCAL_DENIED));
-    }
-
-    @MediumTest
-    public void testLocalUnbindTwice() throws Exception {
-        EmptyConnection conn = new EmptyConnection();
-        getContext().bindService(
-                new Intent(SERVICE_LOCAL_GRANTED), conn, 0);
-        getContext().unbindService(conn);
-        try {
-            getContext().unbindService(conn);
-            fail("No exception thrown on second unbind");
-        } catch (IllegalArgumentException e) {
-            //Log.i("foo", "Unbind exception", e);
+            };
         }
     }
 }
diff --git a/core/tests/coretests/src/android/os/ProcessTest.java b/core/tests/coretests/src/android/os/ProcessTest.java
index b749e71..9de4501 100644
--- a/core/tests/coretests/src/android/os/ProcessTest.java
+++ b/core/tests/coretests/src/android/os/ProcessTest.java
@@ -29,8 +29,10 @@
         assertEquals(Process.BLUETOOTH_UID, Process.getUidForName("bluetooth"));
         assertEquals(Process.FIRST_APPLICATION_UID, Process.getUidForName("u0_a0"));
         assertEquals(UserHandle.getUid(1, Process.SYSTEM_UID), Process.getUidForName("u1_system"));
-        assertEquals(UserHandle.getUid(2, Process.FIRST_ISOLATED_UID),
+        assertEquals(UserHandle.getUid(2, Process.FIRST_APP_ZYGOTE_ISOLATED_UID),
                 Process.getUidForName("u2_i0"));
+        assertEquals(UserHandle.getUid(2, Process.FIRST_ISOLATED_UID),
+                Process.getUidForName("u2_i9000"));
         assertEquals(UserHandle.getUid(3, Process.FIRST_APPLICATION_UID + 100),
                 Process.getUidForName("u3_a100"));
     }
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 1e55828..337663e 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -145,6 +145,7 @@
         InsetsSourceControl ime = controls[2];
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            mController.getSourceConsumer(TYPE_IME).onWindowFocusGained();
             // since there is no focused view, forcefully make IME visible.
             mController.applyImeVisibility(true /* setVisible */);
             mController.show(Type.all());
@@ -160,6 +161,7 @@
             assertFalse(mController.getSourceConsumer(navBar.getType()).isVisible());
             assertFalse(mController.getSourceConsumer(topBar.getType()).isVisible());
             assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+            mController.getSourceConsumer(TYPE_IME).onWindowFocusLost();
         });
         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
     }
@@ -172,12 +174,14 @@
         controls[0] = ime;
         mController.onControlsChanged(controls);
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            mController.getSourceConsumer(TYPE_IME).onWindowFocusGained();
             mController.applyImeVisibility(true);
             mController.cancelExistingAnimation();
             assertTrue(mController.getSourceConsumer(ime.getType()).isVisible());
             mController.applyImeVisibility(false);
             mController.cancelExistingAnimation();
             assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+            mController.getSourceConsumer(TYPE_IME).onWindowFocusLost();
         });
         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
     }
diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
index 971e143..e5fe2d0 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
@@ -18,8 +18,10 @@
 
 import static android.view.InsetsState.TYPE_TOP_BAR;
 
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertTrue;
+
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
@@ -40,6 +42,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
 /**
@@ -60,6 +63,7 @@
     private SurfaceSession mSession = new SurfaceSession();
     private SurfaceControl mLeash;
     @Mock Transaction mMockTransaction;
+    private InsetsSource mSpyInsetsSource;
 
     @Before
     public void setup() {
@@ -77,7 +81,11 @@
             } catch (BadTokenException e) {
                 // activity isn't running, lets ignore BadTokenException.
             }
-            mConsumer = new InsetsSourceConsumer(TYPE_TOP_BAR, new InsetsState(),
+            InsetsState state = new InsetsState();
+            mSpyInsetsSource = Mockito.spy(new InsetsSource(TYPE_TOP_BAR));
+            state.addSource(mSpyInsetsSource);
+
+            mConsumer = new InsetsSourceConsumer(TYPE_TOP_BAR, state,
                     () -> mMockTransaction, new InsetsController(viewRootImpl));
         });
         instrumentation.waitForIdleSync();
@@ -88,14 +96,15 @@
     @Test
     public void testHide() {
         mConsumer.hide();
-        verify(mMockTransaction).hide(eq(mLeash));
+        assertFalse("Consumer should not be visible", mConsumer.isVisible());
+        verify(mSpyInsetsSource).setVisible(eq(false));
     }
 
     @Test
     public void testShow() {
-        mConsumer.hide();
         mConsumer.show();
-        verify(mMockTransaction, atLeastOnce()).show(eq(mLeash));
+        assertTrue("Consumer should be visible", mConsumer.isVisible());
+        verify(mSpyInsetsSource).setVisible(eq(true));
     }
 
     @Test
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index 9f4a619..cf2ef30 100644
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -116,6 +116,7 @@
 
   if (result != 0) {
     LOG(ERROR) << "Failed to open APK '" << path << "' " << ::ErrorCodeString(result);
+    ::CloseArchive(unmanaged_handle);
     return {};
   }
 
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 8a035db..5353869 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -7402,12 +7402,12 @@
         print_complex(value.data, true);
         printf("\n");
     } else if (value.dataType >= Res_value::TYPE_FIRST_COLOR_INT
-            || value.dataType <= Res_value::TYPE_LAST_COLOR_INT) {
+            && value.dataType <= Res_value::TYPE_LAST_COLOR_INT) {
         printf("(color) #%08x\n", value.data);
     } else if (value.dataType == Res_value::TYPE_INT_BOOLEAN) {
         printf("(boolean) %s\n", value.data ? "true" : "false");
     } else if (value.dataType >= Res_value::TYPE_FIRST_INT
-            || value.dataType <= Res_value::TYPE_LAST_INT) {
+            && value.dataType <= Res_value::TYPE_LAST_INT) {
         printf("(int) 0x%08x or %d\n", value.data, value.data);
     } else {
         printf("(unknown type) t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)\n",
diff --git a/libs/hwui/DamageAccumulator.cpp b/libs/hwui/DamageAccumulator.cpp
index 2d2df52..b39f4f2 100644
--- a/libs/hwui/DamageAccumulator.cpp
+++ b/libs/hwui/DamageAccumulator.cpp
@@ -130,7 +130,7 @@
         // calculations. Just give up and expand to DIRTY_MIN/DIRTY_MAX
         temp.set(DIRTY_MIN, DIRTY_MIN, DIRTY_MAX, DIRTY_MAX);
     }
-    out->join(RECT_ARGS(temp));
+    out->join({RECT_ARGS(temp)});
 }
 
 void DamageAccumulator::applyMatrix4Transform(DirtyStack* frame) {
@@ -145,7 +145,7 @@
             // Don't attempt to calculate damage for a perspective transform
             // as the numbers this works with can break the perspective
             // calculations. Just give up and expand to DIRTY_MIN/DIRTY_MAX
-            rect->set(DIRTY_MIN, DIRTY_MIN, DIRTY_MAX, DIRTY_MAX);
+            rect->setLTRB(DIRTY_MIN, DIRTY_MIN, DIRTY_MAX, DIRTY_MAX);
         }
     }
 }
@@ -209,7 +209,7 @@
 
     // Perform clipping
     if (props.getClipDamageToBounds() && !frame->pendingDirty.isEmpty()) {
-        if (!frame->pendingDirty.intersect(0, 0, props.getWidth(), props.getHeight())) {
+        if (!frame->pendingDirty.intersect(SkRect::MakeIWH(props.getWidth(), props.getHeight()))) {
             frame->pendingDirty.setEmpty();
         }
     }
@@ -233,7 +233,7 @@
 }
 
 void DamageAccumulator::dirty(float left, float top, float right, float bottom) {
-    mHead->pendingDirty.join(left, top, right, bottom);
+    mHead->pendingDirty.join({left, top, right, bottom});
 }
 
 void DamageAccumulator::peekAtDirty(SkRect* dest) const {
diff --git a/libs/hwui/DisplayListOps.in b/libs/hwui/DisplayListOps.in
index 2deb565..4a252af 100644
--- a/libs/hwui/DisplayListOps.in
+++ b/libs/hwui/DisplayListOps.in
@@ -49,3 +49,4 @@
 X(DrawAtlas) 
 X(DrawShadowRec)
 X(DrawVectorDrawable)
+X(DrawWebView)
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index c8eb1ca..c0df2fa 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -16,6 +16,7 @@
 
 #include "RecordingCanvas.h"
 
+#include "pipeline/skia/FunctorDrawable.h"
 #include "VectorDrawable.h"
 
 #include "SkAndroidFrameworkUtils.h"
@@ -496,6 +497,16 @@
     SkPaint paint;
     BitmapPalette palette;
 };
+struct DrawWebView final : Op {
+    static const auto kType = Type::DrawWebView;
+    DrawWebView(skiapipeline::FunctorDrawable* drawable) : drawable(sk_ref_sp(drawable)) {}
+    sk_sp<skiapipeline::FunctorDrawable> drawable;
+    // We can't invoke SkDrawable::draw directly, because VkFunctorDrawable expects
+    // SkDrawable::onSnapGpuDrawHandler callback instead of SkDrawable::onDraw.
+    // SkCanvas::drawDrawable/SkGpuDevice::drawDrawable has the logic to invoke
+    // onSnapGpuDrawHandler.
+    void draw(SkCanvas* c, const SkMatrix&) const { c->drawDrawable(drawable.get()); }
+};
 }
 
 template <typename T, typename... Args>
@@ -680,6 +691,9 @@
 void DisplayListData::drawVectorDrawable(VectorDrawableRoot* tree) {
     this->push<DrawVectorDrawable>(0, tree);
 }
+void DisplayListData::drawWebView(skiapipeline::FunctorDrawable* drawable) {
+    this->push<DrawWebView>(0, drawable);
+}
 
 typedef void (*draw_fn)(const void*, SkCanvas*, const SkMatrix&);
 typedef void (*void_fn)(const void*);
@@ -986,5 +1000,9 @@
     fDL->drawVectorDrawable(tree);
 }
 
+void RecordingCanvas::drawWebView(skiapipeline::FunctorDrawable* drawable) {
+    fDL->drawWebView(drawable);
+}
+
 }  // namespace uirenderer
 }  // namespace android
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 16ec877..a79b7c0 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -36,6 +36,10 @@
 namespace android {
 namespace uirenderer {
 
+namespace skiapipeline {
+class FunctorDrawable;
+}
+
 enum class DisplayListOpType : uint8_t {
 #define X(T) T,
 #include "DisplayListOps.in"
@@ -119,6 +123,7 @@
                    SkBlendMode, const SkRect*, const SkPaint*);
     void drawShadowRec(const SkPath&, const SkDrawShadowRec&);
     void drawVectorDrawable(VectorDrawableRoot* tree);
+    void drawWebView(skiapipeline::FunctorDrawable*);
 
     template <typename T, typename... Args>
     void* push(size_t, Args&&...);
@@ -203,6 +208,7 @@
     void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override;
 
     void drawVectorDrawable(VectorDrawableRoot* tree);
+    void drawWebView(skiapipeline::FunctorDrawable*);
 
     /**
      * If "isClipMayBeComplex" returns false, it is guaranteed the current clip is a rectangle.
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index a1be5b7..2ba6fbe 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -361,7 +361,7 @@
 
 void Bitmap::getBounds(SkRect* bounds) const {
     SkASSERT(bounds);
-    bounds->set(0, 0, SkIntToScalar(width()), SkIntToScalar(height()));
+    bounds->setIWH(width(), height());
 }
 
 #ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 0db5133..d67cf8c 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -158,7 +158,7 @@
         functorDrawable = mDisplayList->allocateDrawable<GLFunctorDrawable>(functor, asSkCanvas());
     }
     mDisplayList->mChildFunctors.push_back(functorDrawable);
-    drawDrawable(functorDrawable);
+    mRecorder.drawWebView(functorDrawable);
 #endif
 }
 
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 88a0c6e..aad15ab 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -726,7 +726,7 @@
         // New surface needs a full draw
         dirty->setEmpty();
     } else {
-        if (!dirty->isEmpty() && !dirty->intersect(0, 0, frame.width(), frame.height())) {
+        if (!dirty->isEmpty() && !dirty->intersect(SkRect::MakeIWH(frame.width(), frame.height()))) {
             ALOGW("Dirty " RECT_STRING " doesn't intersect with 0 0 %d %d ?", SK_RECT_ARGS(*dirty),
                   frame.width(), frame.height());
             dirty->setEmpty();
@@ -735,7 +735,7 @@
     }
 
     if (dirty->isEmpty()) {
-        dirty->set(0, 0, frame.width(), frame.height());
+        dirty->setIWH(frame.width(), frame.height());
     }
 
     // At this point dirty is the area of the window to update. However,
@@ -751,7 +751,7 @@
         if (frame.bufferAge() > (int)mSwapHistory.size()) {
             // We don't have enough history to handle this old of a buffer
             // Just do a full-draw
-            dirty->set(0, 0, frame.width(), frame.height());
+            dirty->setIWH(frame.width(), frame.height());
         } else {
             // At this point we haven't yet added the latest frame
             // to the damage history (happens below)
diff --git a/libs/hwui/tests/common/scenes/RectGridAnimation.cpp b/libs/hwui/tests/common/scenes/RectGridAnimation.cpp
index d5ecfaf..80b5cc1 100644
--- a/libs/hwui/tests/common/scenes/RectGridAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/RectGridAnimation.cpp
@@ -37,7 +37,7 @@
             SkRegion region;
             for (int xOffset = 0; xOffset < 200; xOffset += 2) {
                 for (int yOffset = 0; yOffset < 200; yOffset += 2) {
-                    region.op(xOffset, yOffset, xOffset + 1, yOffset + 1, SkRegion::kUnion_Op);
+                    region.op({xOffset, yOffset, xOffset + 1, yOffset + 1}, SkRegion::kUnion_Op);
                 }
             }
 
diff --git a/location/java/android/location/GnssCapabilities.java b/location/java/android/location/GnssCapabilities.java
index 36fe8da..2e2f984 100644
--- a/location/java/android/location/GnssCapabilities.java
+++ b/location/java/android/location/GnssCapabilities.java
@@ -16,6 +16,7 @@
 
 package android.location;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 
 /**
@@ -164,6 +165,7 @@
         return hasCapability(MEASUREMENT_CORRECTIONS_REFLECTING_PLANE);
     }
 
+    @NonNull
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder("GnssCapabilities: ( ");
diff --git a/location/java/android/location/GnssMeasurementCorrections.java b/location/java/android/location/GnssMeasurementCorrections.java
index 3e32c21..a23213f 100644
--- a/location/java/android/location/GnssMeasurementCorrections.java
+++ b/location/java/android/location/GnssMeasurementCorrections.java
@@ -176,6 +176,7 @@
                 }
             };
 
+    @NonNull
     @Override
     public String toString() {
         final String format = "   %-29s = %s\n";
diff --git a/location/java/android/location/GnssReflectingPlane.java b/location/java/android/location/GnssReflectingPlane.java
index 9d05287..1acdd1e 100644
--- a/location/java/android/location/GnssReflectingPlane.java
+++ b/location/java/android/location/GnssReflectingPlane.java
@@ -107,6 +107,7 @@
                 }
             };
 
+    @NonNull
     @Override
     public String toString() {
         final String format = "   %-29s = %s\n";
diff --git a/location/java/android/location/GnssSingleSatCorrection.java b/location/java/android/location/GnssSingleSatCorrection.java
index e901909..aeca562 100644
--- a/location/java/android/location/GnssSingleSatCorrection.java
+++ b/location/java/android/location/GnssSingleSatCorrection.java
@@ -268,6 +268,7 @@
                 }
             };
 
+    @NonNull
     @Override
     public String toString() {
         final String format = "   %-29s = %s\n";
diff --git a/location/java/android/location/GpsClock.java b/location/java/android/location/GpsClock.java
index 52ba60e..f123766 100644
--- a/location/java/android/location/GpsClock.java
+++ b/location/java/android/location/GpsClock.java
@@ -16,6 +16,7 @@
 
 package android.location;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -437,6 +438,7 @@
         return 0;
     }
 
+    @NonNull
     @Override
     public String toString() {
         final String format = "   %-15s = %s\n";
diff --git a/location/java/android/location/GpsMeasurement.java b/location/java/android/location/GpsMeasurement.java
index 51718b8..27a8189 100644
--- a/location/java/android/location/GpsMeasurement.java
+++ b/location/java/android/location/GpsMeasurement.java
@@ -16,6 +16,7 @@
 
 package android.location;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -1244,6 +1245,7 @@
         return 0;
     }
 
+    @NonNull
     @Override
     public String toString() {
         final String format = "   %-29s = %s\n";
diff --git a/location/java/android/location/GpsMeasurementsEvent.java b/location/java/android/location/GpsMeasurementsEvent.java
index 1cd1fb4..d69158d 100644
--- a/location/java/android/location/GpsMeasurementsEvent.java
+++ b/location/java/android/location/GpsMeasurementsEvent.java
@@ -140,6 +140,7 @@
         parcel.writeTypedArray(measurementsArray, flags);
     }
 
+    @NonNull
     @Override
     public String toString() {
         StringBuilder builder = new StringBuilder("[ GpsMeasurementsEvent:\n\n");
diff --git a/location/java/android/location/GpsNavigationMessage.java b/location/java/android/location/GpsNavigationMessage.java
index 77f0113..6eeea26 100644
--- a/location/java/android/location/GpsNavigationMessage.java
+++ b/location/java/android/location/GpsNavigationMessage.java
@@ -290,6 +290,7 @@
         return 0;
     }
 
+    @NonNull
     @Override
     public String toString() {
         final String format = "   %-15s = %s\n";
diff --git a/location/java/android/location/GpsNavigationMessageEvent.java b/location/java/android/location/GpsNavigationMessageEvent.java
index 2aa685c..f60e5c7 100644
--- a/location/java/android/location/GpsNavigationMessageEvent.java
+++ b/location/java/android/location/GpsNavigationMessageEvent.java
@@ -109,6 +109,7 @@
         parcel.writeParcelable(mNavigationMessage, flags);
     }
 
+    @NonNull
     @Override
     public String toString() {
         StringBuilder builder = new StringBuilder("[ GpsNavigationMessageEvent:\n\n");
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index a05d850..0902acf 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -734,6 +734,7 @@
         }
     }
 
+    @NonNull
     @Override
     public String toString() {
         StringBuilder s = new StringBuilder();
diff --git a/location/lib/Android.bp b/location/lib/Android.bp
index b15cc5c..ff6921d 100644
--- a/location/lib/Android.bp
+++ b/location/lib/Android.bp
@@ -16,13 +16,12 @@
 
 java_sdk_library {
     name: "com.android.location.provider",
-    srcs: ["java/**/*.java"],
+    srcs: [
+        "java/**/*.java",
+        ":framework-srcs",
+    ],
     libs: [
         "androidx.annotation_annotation",
     ],
     api_packages: ["com.android.location.provider"],
-    srcs_lib: "framework-minus-apex",
-    // TODO(b/70046217): remove core/java and android below. It was added to provide definitions for
-    // types like android.os.Bundle
-    srcs_lib_whitelist_pkgs: ["android", "com.android.internal.location"],
 }
diff --git a/media/Android.bp b/media/Android.bp
index ef32239..a59b3e7 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -45,13 +45,6 @@
 }
 
 filegroup {
-    name: "updatable-media-srcs-without-aidls",
-    srcs : [
-        ":mediasession2-srcs-without-aidls",
-    ],
-}
-
-filegroup {
     name: "mediasession2-srcs",
     srcs: [
         "apex/java/android/media/Controller2Link.java",
@@ -71,19 +64,6 @@
 }
 
 filegroup {
-    name: "mediasession2-srcs-without-aidls",
-    srcs: [
-        ":mediasession2-srcs",
-    ],
-    exclude_srcs: [
-        "apex/java/android/media/IMediaController2.aidl",
-        "apex/java/android/media/IMediaSession2.aidl",
-        "apex/java/android/media/IMediaSession2Service.aidl",
-    ],
-    path: "apex/java",
-}
-
-filegroup {
     name: "mediaplayer2-srcs",
     srcs: [
         "apex/java/android/media/CloseGuard.java",
@@ -113,21 +93,21 @@
 droidstubs {
     name: "updatable-media-stubs",
     srcs: [
-        ":updatable-media-srcs-without-aidls",
+        ":updatable-media-srcs",
         ":framework-media-annotation-srcs",
     ],
     args: metalava_updatable_media_args,
-    // Ideally, sdk_version here should be "current_system", but "current - 1" is used
-    // to avoid dependency cycle with framework.
-    sdk_version: "28",
+    aidl: {
+        // TODO(b/135922046) remove this
+        include_dirs: ["frameworks/base/core/java"],
+    },
+    sdk_version: "system_current",
 }
 
 java_library {
     name: "updatable_media_stubs",
     srcs: [":updatable-media-stubs"],
-    // Ideally, sdk_version here should be "current_system", but "current - 1" is used
-    // to avoid dependency cycle with framework.
-    sdk_version: "28",
+    sdk_version: "system_current",
 }
 
 java_library {
diff --git a/media/java/android/media/AudioFocusInfo.java b/media/java/android/media/AudioFocusInfo.java
index ee89509..675cf73 100644
--- a/media/java/android/media/AudioFocusInfo.java
+++ b/media/java/android/media/AudioFocusInfo.java
@@ -17,6 +17,7 @@
 package android.media;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.os.Parcel;
@@ -155,7 +156,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (this == obj)
             return true;
         if (obj == null)
diff --git a/media/java/android/media/audiopolicy/AudioProductStrategy.java b/media/java/android/media/audiopolicy/AudioProductStrategy.java
index e456dad..2799d46 100644
--- a/media/java/android/media/audiopolicy/AudioProductStrategy.java
+++ b/media/java/android/media/audiopolicy/AudioProductStrategy.java
@@ -299,6 +299,7 @@
                 }
             };
 
+    @NonNull
     @Override
     public String toString() {
         StringBuilder s = new StringBuilder();
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 6fd3342..92fb31b 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -1006,7 +1006,7 @@
          * @return {@code true} if equals, {@code false} otherwise
          */
         @Override
-        public boolean equals(Object obj) {
+        public boolean equals(@Nullable Object obj) {
             if (!(obj instanceof RemoteUserInfo)) {
                 return false;
             }
diff --git a/media/java/android/media/tv/TvContentRating.java b/media/java/android/media/tv/TvContentRating.java
index 6197c70..9e671b1 100644
--- a/media/java/android/media/tv/TvContentRating.java
+++ b/media/java/android/media/tv/TvContentRating.java
@@ -179,6 +179,10 @@
  *         <td>TV content rating system for Canada (French)</td>
  *     </tr>
  *     <tr>
+ *         <td>DTMB</td>
+ *         <td>DTMB content rating system</td>
+ *     </tr>
+ *     <tr>
  *         <td>DVB</td>
  *         <td>DVB content rating system</td>
  *     </tr>
@@ -199,10 +203,18 @@
  *         <td>TV content rating system for South Korea</td>
  *     </tr>
  *     <tr>
+ *         <td>NZ_TV</td>
+ *         <td>TV content rating system for New Zealand</td>
+ *     </tr>
+ *     <tr>
  *         <td>SG_TV</td>
  *         <td>TV content rating system for Singapore</td>
  *     </tr>
  *     <tr>
+ *         <td>TH_TV</td>
+ *         <td>TV content rating system for Thailand</td>
+ *     </tr>
+ *     <tr>
  *         <td>US_MV</td>
  *         <td>Movie content rating system for the United States</td>
  *     </tr>
@@ -356,6 +368,67 @@
  *         <td>Only to be viewed by adults</td>
  *     </tr>
  *     <tr>
+ *         <td valign="top" rowspan="15">DTMB</td>
+ *         <td>DTMB_4</td>
+ *         <td>Recommended for ages 4 and over</td>
+ *     </tr>
+ *     <tr>
+ *         <td>DTMB_5</td>
+ *         <td>Recommended for ages 5 and over</td>
+ *     </tr>
+ *     <tr>
+ *         <td>DTMB_6</td>
+ *         <td>Recommended for ages 6 and over</td>
+ *     </tr>
+ *     <tr>
+ *         <td>DTMB_7</td>
+ *         <td>Recommended for ages 7 and over</td>
+ *     </tr>
+ *     <tr>
+ *         <td>DTMB_8</td>
+ *         <td>Recommended for ages 8 and over</td>
+ *     </tr>
+ *     <tr>
+ *         <td>DTMB_9</td>
+ *         <td>Recommended for ages 9 and over</td>
+ *     </tr>
+ *     <tr>
+ *         <td>DTMB_10</td>
+ *         <td>Recommended for ages 10 and over</td>
+ *     </tr>
+ *     <tr>
+ *         <td>DTMB_11</td>
+ *         <td>Recommended for ages 11 and over</td>
+ *     </tr>
+ *     <tr>
+ *         <td>DTMB_12</td>
+ *         <td>Recommended for ages 12 and over</td>
+ *     </tr>
+ *     <tr>
+ *         <td>DTMB_13</td>
+ *         <td>Recommended for ages 13 and over</td>
+ *     </tr>
+ *     <tr>
+ *         <td>DTMB_14</td>
+ *         <td>Recommended for ages 14 and over</td>
+ *     </tr>
+ *     <tr>
+ *         <td>DTMB_15</td>
+ *         <td>Recommended for ages 15 and over</td>
+ *     </tr>
+ *     <tr>
+ *         <td>DTMB_16</td>
+ *         <td>Recommended for ages 16 and over</td>
+ *     </tr>
+ *     <tr>
+ *         <td>DTMB_17</td>
+ *         <td>Recommended for ages 17 and over</td>
+ *     </tr>
+ *     <tr>
+ *         <td>DTMB_18</td>
+ *         <td>Recommended for ages 18 and over</td>
+ *     </tr>
+ *     <tr>
  *         <td valign="top" rowspan="15">DVB</td>
  *         <td>DVB_4</td>
  *         <td>Recommended for ages 4 and over</td>
@@ -648,6 +721,22 @@
  *         <td>For adults only</td>
  *     </tr>
  *     <tr>
+ *         <td valign="top" rowspan="3">NZ_TV</td>
+ *         <td>NZ_TV_G</td>
+ *         <td>Programmes which exclude material likely to be unsuitable for children. Programmes
+ *         may not necessarily be designed for child viewers but should not contain material likely
+ *         to alarm or distress them.</td>
+ *     </tr>
+ *     <tr>
+ *         <td>NZ_TV_PGR</td>
+ *         <td>Programmes containing material more suited for mature audiences but not necessarily
+ *         unsuitable for child viewers when subject to the guidance of a parent or an adult.</td>
+ *     </tr>
+ *     <tr>
+ *         <td>NZ_TV_AO</td>
+ *         <td>Programmes containing adult themes and directed primarily at mature audiences.</td>
+ *     </tr>
+ *     <tr>
  *         <td valign="top" rowspan="6">SG_TV</td>
  *         <td>SG_TV_G</td>
  *         <td>Suitable for all ages</td>
@@ -674,6 +763,31 @@
  *         <td>Suitable for adults aged 21 and above</td>
  *     </tr>
  *     <tr>
+ *         <td valign="top" rowspan="6">TH_TV</td>
+ *         <td>TH_TV_4</td>
+ *         <td>Suitable for audiences 3 to 5 years of age</td>
+ *     </tr>
+ *     <tr>
+ *         <td>TH_TV_6</td>
+ *         <td>Suitable for audiences 6 to 12 years of age</td>
+ *     </tr>
+ *     <tr>
+ *         <td>TH_TV_10</td>
+ *         <td>Suitable for all audiences</td>
+ *     </tr>
+ *     <tr>
+ *         <td>TH_TV_13</td>
+ *         <td>Parental guidance suggested for viewers age below 13</td>
+ *     </tr>
+ *     <tr>
+ *         <td>TH_TV_18</td>
+ *         <td>Parental guidance suggested for viewers age below 18</td>
+ *     </tr>
+ *     <tr>
+ *         <td>TH_TV_19</td>
+ *         <td>Not suitable for children and teenagers</td>
+ *     </tr>
+ *     <tr>
  *         <td valign="top" rowspan="5">US_MV</td>
  *         <td>US_MV_G</td>
  *         <td>General audiences</td>
diff --git a/media/java/android/media/tv/TvInputHardwareInfo.java b/media/java/android/media/tv/TvInputHardwareInfo.java
index 5b316be..b12f7c5 100644
--- a/media/java/android/media/tv/TvInputHardwareInfo.java
+++ b/media/java/android/media/tv/TvInputHardwareInfo.java
@@ -19,12 +19,14 @@
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.hardware.tv.input.V1_0.Constants;
 import android.media.AudioManager;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Log;
+
 import java.lang.annotation.Retention;
 
 /**
@@ -141,6 +143,7 @@
         return mCableConnectionStatus;
     }
 
+    @NonNull
     @Override
     public String toString() {
         StringBuilder b = new StringBuilder(128);
diff --git a/media/java/android/media/tv/TvStreamConfig.java b/media/java/android/media/tv/TvStreamConfig.java
index f012b46..7ea93b4 100644
--- a/media/java/android/media/tv/TvStreamConfig.java
+++ b/media/java/android/media/tv/TvStreamConfig.java
@@ -16,6 +16,8 @@
 
 package android.media.tv;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -87,6 +89,7 @@
         return mGeneration;
     }
 
+    @NonNull
     @Override
     public String toString() {
         return "TvStreamConfig {mStreamId=" + mStreamId + ";" + "mType=" + mType + ";mGeneration="
@@ -163,7 +166,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (obj == null) return false;
         if (!(obj instanceof TvStreamConfig)) return false;
 
diff --git a/media/java/android/media/tv/TvTrackInfo.java b/media/java/android/media/tv/TvTrackInfo.java
index e09eeb8..ea00d6e 100644
--- a/media/java/android/media/tv/TvTrackInfo.java
+++ b/media/java/android/media/tv/TvTrackInfo.java
@@ -394,6 +394,7 @@
          *
          * @param encrypted The encryption status of the track.
          */
+        @NonNull
         public Builder setEncrypted(boolean encrypted) {
             mEncrypted = encrypted;
             return this;
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 8d420e2..cbc820b 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -743,8 +743,8 @@
 }
 
 status_t JMediaCodec::getMetrics(JNIEnv *, MediaAnalyticsItem * &reply) const {
-
-    status_t status = mCodec->getMetrics(reply);
+    mediametrics_handle_t reply2 = MediaAnalyticsItem::convert(reply);
+    status_t status = mCodec->getMetrics(reply2);
     return status;
 }
 
@@ -1848,7 +1848,7 @@
     }
 
     // get what we have for the metrics from the codec
-    MediaAnalyticsItem *item = NULL;
+    MediaAnalyticsItem *item = 0;
 
     status_t err = codec->getMetrics(env, item);
     if (err != OK) {
@@ -1860,7 +1860,7 @@
 
     // housekeeping
     delete item;
-    item = NULL;
+    item = 0;
 
     return mybundle;
 }
diff --git a/media/jni/android_media_MediaCodecList.cpp b/media/jni/android_media_MediaCodecList.cpp
index 923d1d2..307d80d 100644
--- a/media/jni/android_media_MediaCodecList.cpp
+++ b/media/jni/android_media_MediaCodecList.cpp
@@ -26,6 +26,7 @@
 
 #include <utils/Vector.h>
 
+#include <mutex>
 #include <vector>
 
 #include "android_runtime/AndroidRuntime.h"
diff --git a/media/lib/signer/Android.bp b/media/lib/signer/Android.bp
index 338ec12..85a007f 100644
--- a/media/lib/signer/Android.bp
+++ b/media/lib/signer/Android.bp
@@ -16,8 +16,9 @@
 
 java_sdk_library {
     name: "com.android.mediadrm.signer",
-    srcs: ["java/**/*.java"],
+    srcs: [
+        "java/**/*.java",
+        ":framework-srcs",
+    ],
     api_packages: ["com.android.mediadrm.signer"],
-    srcs_lib: "framework-minus-apex",
-    srcs_lib_whitelist_pkgs: ["android.media"],
 }
diff --git a/mime/Android.bp b/mime/Android.bp
deleted file mode 100644
index 9303755..0000000
--- a/mime/Android.bp
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-java_library {
-    name: "mimemap",
-    visibility: [
-        "//cts/tests/tests/mimemap:__subpackages__",
-        "//frameworks/base:__subpackages__",
-    ],
-
-    srcs: [
-        "java/android/content/type/MimeMapImpl.java",
-    ],
-
-    java_resources: [
-        ":debian.mime.types",
-        ":android.mime.types",
-    ],
-
-    sdk_version: "core_platform",
-}
-
-filegroup {
-    name: "android.mime.types",
-    visibility: [
-        "//visibility:private",
-    ],
-    path: "java-res/",
-    srcs: [
-        "java-res/android.mime.types",
-    ],
-}
diff --git a/mime/java-res/android.mime.types b/mime/java-res/android.mime.types
deleted file mode 100644
index 1ca912e..0000000
--- a/mime/java-res/android.mime.types
+++ /dev/null
@@ -1,146 +0,0 @@
-
-###############################################################################
-#
-# Android-specific MIME type <-> extension mappings
-#
-# Each line below defines an mapping from one MIME type to the first of the
-# listed extensions, and from listed extension back to the MIME type.
-# A mapping overrides any previous mapping _from_ that same MIME type or
-# extension (put() semantics), unless that MIME type / extension is prefixed with '?'
-# (putIfAbsent() semantics).
-#
-#
-###############################################################################
-#
-# EXAMPLES
-#
-# A line of the form:
-#
-#    ?mime ext1 ?ext2 ext3
-#
-# affects the current mappings along the lines of the following pseudo code:
-#
-#    mimeToExt.putIfAbsent("mime", "ext1");
-#    extToMime.put("ext1", "mime");
-#    extToMime.putIfAbsent("ext2", "mime");
-#    extToMime.put("ext3", "mime");
-#
-# The line:
-#
-#     ?text/plain txt
-#
-# leaves any earlier mapping for "text/plain" untouched, or maps that MIME type
-# to the file extension ".txt" if there is no earlier mapping. The line also
-# sets the mapping from file extension ".txt" to be the MIME type "text/plain",
-# regardless of whether a previous mapping existed.
-#
-###############################################################################
-
-
-# File extensions that Android wants to override to point to the given MIME type.
-#
-# After processing a line of the form:
-# ?<mimeType> <extension1> <extension2>
-# If <mimeType> was not already mapped to an extension then it will be
-# mapped to <extension1>.
-# <extension1> and <extension2> are mapped (or remapped) to <mimeType>.
-
-?application/epub+zip epub
-?application/pkix-cert cer
-?application/rss+xml rss
-?application/vnd.android.ota ota
-?application/vnd.apple.mpegurl m3u8
-?application/vnd.ms-pki.stl stl
-?application/vnd.ms-powerpoint pot
-?application/vnd.ms-wpl wpl
-?application/vnd.stardivision.impress sdp
-?application/vnd.stardivision.writer vor
-?application/vnd.youtube.yt yt
-?application/x-android-drm-fl fl
-?application/x-flac flac
-?application/x-font pcf
-?application/x-mpegurl m3u m3u8
-?application/x-pem-file pem
-?application/x-pkcs12 p12 pfx
-?application/x-webarchive webarchive
-?application/x-webarchive-xml webarchivexml
-?application/x-x509-server-cert crt
-?application/x-x509-user-cert crt
-
-?audio/3gpp 3gpp
-?audio/aac-adts aac
-?audio/imelody imy
-?audio/midi rtttl xmf
-?audio/mobile-xmf mxmf
-?audio/mp4 m4a
-?audio/mpegurl m3u
-?audio/sp-midi smf
-?audio/x-matroska mka
-?audio/x-pn-realaudio ra
-
-?image/bmp bmp
-?image/heic heic
-?image/heic-sequence heics
-?image/heif heif hif
-?image/heif-sequence heifs
-?image/ico cur
-?image/webp webp
-?image/x-adobe-dng dng
-?image/x-fuji-raf raf
-?image/x-icon ico
-?image/x-nikon-nrw nrw
-?image/x-panasonic-rw2 rw2
-?image/x-pentax-pef pef
-?image/x-samsung-srw srw
-?image/x-sony-arw arw
-
-?text/comma-separated-values csv
-?text/plain diff po
-?text/rtf rtf
-?text/text phps
-?text/xml xml
-?text/x-vcard vcf
-
-?video/3gpp2 3gpp2 3g2
-?video/3gpp 3gpp
-?video/avi avi
-?video/m4v m4v
-?video/mp2p mpeg
-?video/mp2t m2ts mts
-?video/mp2ts ts
-?video/vnd.youtube.yt yt
-?video/x-webex wrf
-
-# Optional additions that should not override any previous mapping.
-
-?application/x-wifi-config ?xml
-
-# Special cases where Android has a strong opinion about mappings, so we
-# define them very last and make them override in both directions (no "?").
-#
-# Lines here are of the form:
-# <mimeType> <extension1> <extension2> ...
-#
-# After processing each line,
-#   <mimeType> is mapped to <extension1>
-#   <extension1>, <extension2>, ... are all mapped to <mimeType>
-# This overrides any mappings for this <mimeType> / for these extensions
-# that may have been defined earlier.
-
-application/pgp-signature pgp
-application/x-x509-ca-cert crt
-audio/aac aac
-audio/basic snd
-audio/flac flac
-audio/midi rtx
-audio/mpeg mp3 m4a m4r
-audio/x-mpegurl m3u m3u8
-image/jpeg jpg
-image/x-ms-bmp bmp
-text/plain txt
-text/x-c++hdr hpp
-text/x-c++src cpp
-video/3gpp 3gpp
-video/mpeg mpeg
-video/quicktime mov
-video/x-matroska mkv
diff --git a/mime/java/android/content/type/MimeMapImpl.java b/mime/java/android/content/type/MimeMapImpl.java
deleted file mode 100644
index c904ea3..0000000
--- a/mime/java/android/content/type/MimeMapImpl.java
+++ /dev/null
@@ -1,194 +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.content.type;
-
-import libcore.net.MimeMap;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-
-/**
- * Default implementation of {@link MimeMap}, a bidirectional mapping between
- * MIME types and file extensions.
- *
- * This default mapping is loaded from data files that start with some mappings
- * recognized by IANA plus some custom extensions and overrides.
- *
- * @hide
- */
-public class MimeMapImpl extends MimeMap {
-
-    /**
-     * Creates and returns a new {@link MimeMapImpl} instance that implements.
-     * Android's default mapping between MIME types and extensions.
-     */
-    public static MimeMapImpl createDefaultInstance() {
-        return parseFromResources("/mime.types", "/android.mime.types");
-    }
-
-    private static final Pattern SPLIT_PATTERN = Pattern.compile("\\s+");
-
-    /**
-     * Note: These maps only contain lowercase keys/values, regarded as the
-     * {@link #toLowerCase(String) canonical form}.
-     *
-     * <p>This is the case for both extensions and MIME types. The mime.types
-     * data file contains examples of mixed-case MIME types, but some applications
-     * use the lowercase version of these same types. RFC 2045 section 2 states
-     * that MIME types are case insensitive.
-     */
-    private final Map<String, String> mMimeTypeToExtension;
-    private final Map<String, String> mExtensionToMimeType;
-
-    public MimeMapImpl(Map<String, String> mimeTypeToExtension,
-            Map<String, String> extensionToMimeType) {
-        this.mMimeTypeToExtension = new HashMap<>(mimeTypeToExtension);
-        for (Map.Entry<String, String> entry : mimeTypeToExtension.entrySet()) {
-            checkValidMimeType(entry.getKey());
-            checkValidExtension(entry.getValue());
-        }
-        this.mExtensionToMimeType = new HashMap<>(extensionToMimeType);
-        for (Map.Entry<String, String> entry : extensionToMimeType.entrySet()) {
-            checkValidExtension(entry.getKey());
-            checkValidMimeType(entry.getValue());
-        }
-    }
-
-    private static void checkValidMimeType(String s) {
-        if (MimeMap.isNullOrEmpty(s) || !s.equals(MimeMap.toLowerCase(s))) {
-            throw new IllegalArgumentException("Invalid MIME type: " + s);
-        }
-    }
-
-    private static void checkValidExtension(String s) {
-        if (MimeMap.isNullOrEmpty(s) || !s.equals(MimeMap.toLowerCase(s))) {
-            throw new IllegalArgumentException("Invalid extension: " + s);
-        }
-    }
-
-    static MimeMapImpl parseFromResources(String... resourceNames) {
-        Map<String, String> mimeTypeToExtension = new HashMap<>();
-        Map<String, String> extensionToMimeType = new HashMap<>();
-        for (String resourceName : resourceNames) {
-            parseTypes(mimeTypeToExtension, extensionToMimeType, resourceName);
-        }
-        return new MimeMapImpl(mimeTypeToExtension, extensionToMimeType);
-    }
-
-    /**
-     * An element of a *mime.types file: A MIME type or an extension, with an optional
-     * prefix of "?" (if not overriding an earlier value).
-     */
-    private static class Element {
-        public final boolean keepExisting;
-        public final String s;
-
-        Element(boolean keepExisting, String value) {
-            this.keepExisting = keepExisting;
-            this.s = toLowerCase(value);
-            if (value.isEmpty()) {
-                throw new IllegalArgumentException();
-            }
-        }
-
-        public String toString() {
-            return keepExisting ? ("?" + s) : s;
-        }
-    }
-
-    private static String maybePut(Map<String, String> map, Element keyElement, String value) {
-        if (keyElement.keepExisting) {
-            return map.putIfAbsent(keyElement.s, value);
-        } else {
-            return map.put(keyElement.s, value);
-        }
-    }
-
-    private static void parseTypes(Map<String, String> mimeTypeToExtension,
-            Map<String, String> extensionToMimeType, String resource) {
-        try (BufferedReader r = new BufferedReader(
-                new InputStreamReader(MimeMapImpl.class.getResourceAsStream(resource)))) {
-            String line;
-            while ((line = r.readLine()) != null) {
-                int commentPos = line.indexOf('#');
-                if (commentPos >= 0) {
-                    line = line.substring(0, commentPos);
-                }
-                line = line.trim();
-                // The first time a MIME type is encountered it is mapped to the first extension
-                // listed in its line. The first time an extension is encountered it is mapped
-                // to the MIME type.
-                //
-                // When encountering a previously seen MIME type or extension, then by default
-                // the later ones override earlier mappings (put() semantics); however if a MIME
-                // type or extension is prefixed with '?' then any earlier mapping _from_ that
-                // MIME type / extension is kept (putIfAbsent() semantics).
-                final String[] split = SPLIT_PATTERN.split(line);
-                if (split.length <= 1) {
-                    // Need mimeType + at least one extension to make a mapping.
-                    // "mime.types" files may also contain lines with just a mimeType without
-                    // an extension but we skip them as they provide no mapping info.
-                    continue;
-                }
-                List<Element> lineElements = new ArrayList<>(split.length);
-                for (String s : split) {
-                    boolean keepExisting = s.startsWith("?");
-                    if (keepExisting) {
-                        s = s.substring(1);
-                    }
-                    if (s.isEmpty()) {
-                        throw new IllegalArgumentException("Invalid entry in '" + line + "'");
-                    }
-                    lineElements.add(new Element(keepExisting, s));
-                }
-
-                // MIME type -> first extension (one mapping)
-                // This will override any earlier mapping from this MIME type to another
-                // extension, unless this MIME type was prefixed with '?'.
-                Element mimeElement = lineElements.get(0);
-                List<Element> extensionElements = lineElements.subList(1, lineElements.size());
-                String firstExtension = extensionElements.get(0).s;
-                maybePut(mimeTypeToExtension, mimeElement, firstExtension);
-
-                // extension -> MIME type (one or more mappings).
-                // This will override any earlier mapping from this extension to another
-                // MIME type, unless this extension was prefixed with '?'.
-                for (Element extensionElement : extensionElements) {
-                    maybePut(extensionToMimeType, extensionElement, mimeElement.s);
-                }
-            }
-        } catch (IOException | RuntimeException e) {
-            throw new RuntimeException("Failed to parse " + resource, e);
-        }
-    }
-
-    @Override
-    protected String guessExtensionFromLowerCaseMimeType(String mimeType) {
-        return mMimeTypeToExtension.get(mimeType);
-    }
-
-    @Override
-    protected String guessMimeTypeFromLowerCaseExtension(String extension) {
-        return mExtensionToMimeType.get(extension);
-    }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java
index 78bb1bc..013c63b 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java
@@ -192,23 +192,28 @@
         }
     }
 
-    // Set button text based on security lock type
+    // Set button text based on screen lock type
     private void setButtonText() {
         LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
         int passwordQuality = lockPatternUtils.getActivePasswordQuality(mUid);
         switch (passwordQuality) {
             // PIN
+            case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
             case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
+                mButton.setText(R.string.unlock_dialog_button_text_pin);
+                break;
             // Pattern
             case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
                 mButton.setText(R.string.unlock_dialog_button_text_pattern);
                 break;
             // Password
-            case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
+            case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
+            case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
+            case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
                 mButton.setText(R.string.unlock_dialog_button_text_password);
                 break;
             default:
-                Log.e(TAG, "Encountered unexpected security type when attempting to set "
+                Log.e(TAG, "Encountered unexpected screen lock type when attempting to set "
                         + "button text:" + passwordQuality);
         }
     }
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index 7760e0e..9c8345da 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -24,6 +24,8 @@
         "SettingsLibProgressBar",
         "SettingsLibAdaptiveIcon",
         "SettingsLibRadioButtonPreference",
+        "WifiTrackerLib",
+        "SettingsLibDisplayDensityUtils",
     ],
 
     // ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_SHARED_JAVA_LIBRARIES
diff --git a/packages/SettingsLib/DisplayDensityUtils/Android.bp b/packages/SettingsLib/DisplayDensityUtils/Android.bp
new file mode 100644
index 0000000..27d0cb5
--- /dev/null
+++ b/packages/SettingsLib/DisplayDensityUtils/Android.bp
@@ -0,0 +1,7 @@
+android_library {
+    name: "SettingsLibDisplayDensityUtils",
+
+    srcs: ["src/**/*.java"],
+
+    min_sdk_version: "21",
+}
diff --git a/packages/SettingsLib/DisplayDensityUtils/AndroidManifest.xml b/packages/SettingsLib/DisplayDensityUtils/AndroidManifest.xml
new file mode 100644
index 0000000..0a4e2bb
--- /dev/null
+++ b/packages/SettingsLib/DisplayDensityUtils/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?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.display">
+
+</manifest>
diff --git a/packages/SettingsLib/DisplayDensityUtils/src/com/android/settingslib/display/DisplayDensityConfiguration.java b/packages/SettingsLib/DisplayDensityUtils/src/com/android/settingslib/display/DisplayDensityConfiguration.java
new file mode 100644
index 0000000..284a902
--- /dev/null
+++ b/packages/SettingsLib/DisplayDensityUtils/src/com/android/settingslib/display/DisplayDensityConfiguration.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.settingslib.display;
+
+import android.os.AsyncTask;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+import android.view.IWindowManager;
+import android.view.WindowManagerGlobal;
+
+/** Utility methods for controlling the display density. */
+public class DisplayDensityConfiguration {
+    private static final String LOG_TAG = "DisplayDensityConfig";
+
+    /**
+     * Returns the default density for the specified display.
+     *
+     * @param displayId the identifier of the display
+     * @return the default density of the specified display, or {@code -1} if the display does not
+     *     exist or the density could not be obtained
+     */
+    static int getDefaultDisplayDensity(int displayId) {
+        try {
+            final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+            return wm.getInitialDisplayDensity(displayId);
+        } catch (RemoteException exc) {
+            return -1;
+        }
+    }
+
+    /**
+     * Asynchronously applies display density changes to the specified display.
+     *
+     * <p>The change will be applied to the user specified by the value of {@link
+     * UserHandle#myUserId()} at the time the method is called.
+     *
+     * @param displayId the identifier of the display to modify
+     */
+    public static void clearForcedDisplayDensity(final int displayId) {
+        final int userId = UserHandle.myUserId();
+        AsyncTask.execute(
+                () -> {
+                    try {
+                        final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+                        wm.clearForcedDisplayDensityForUser(displayId, userId);
+                    } catch (RemoteException exc) {
+                        Log.w(LOG_TAG, "Unable to clear forced display density setting");
+                    }
+                });
+    }
+
+    /**
+     * Asynchronously applies display density changes to the specified display.
+     *
+     * <p>The change will be applied to the user specified by the value of {@link
+     * UserHandle#myUserId()} at the time the method is called.
+     *
+     * @param displayId the identifier of the display to modify
+     * @param density the density to force for the specified display
+     */
+    public static void setForcedDisplayDensity(final int displayId, final int density) {
+        final int userId = UserHandle.myUserId();
+        AsyncTask.execute(
+                () -> {
+                    try {
+                        final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+                        wm.setForcedDisplayDensityForUser(displayId, density, userId);
+                    } catch (RemoteException exc) {
+                        Log.w(LOG_TAG, "Unable to save forced display density setting");
+                    }
+                });
+    }
+}
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index eb6160a..75344c4 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -376,7 +376,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="8424148009038666065">"ప్రొటానోమలీ (ఎరుపు-ఆకుపచ్చ రంగు)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="481725854987912389">"ట్రైటనోమలీ (నీలం-పసుపు రంగు)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"రంగు సవరణ"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ఈ లక్షణం ప్రయోగాత్మకమైనది మరియు పనితీరుపై ప్రభావం చూపవచ్చు."</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ఈ ఫీచ‌ర్‌ ప్రయోగాత్మకమైనది, పనితీరుపై ప్రభావం చూపవచ్చు."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> ద్వారా భర్తీ చేయబడింది"</string>
     <string name="power_remaining_settings_home_page" msgid="4845022416859002011">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="6123167166221295462">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> సమయం మిగిలి ఉంది"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
index 99d48d3..aac7fc3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
@@ -34,11 +34,14 @@
 
 import com.android.settingslib.R;
 
+import libcore.timezone.CountryTimeZones;
+import libcore.timezone.CountryTimeZones.TimeZoneMapping;
 import libcore.timezone.TimeZoneFinder;
 
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -387,7 +390,21 @@
 
         @VisibleForTesting
         public List<String> lookupTimeZoneIdsByCountry(String country) {
-            return TimeZoneFinder.getInstance().lookupTimeZoneIdsByCountry(country);
+            final CountryTimeZones countryTimeZones =
+                    TimeZoneFinder.getInstance().lookupCountryTimeZones(country);
+            if (countryTimeZones == null) {
+                return null;
+            }
+            final List<TimeZoneMapping> mappings = countryTimeZones.getTimeZoneMappings();
+            return extractTimeZoneIds(mappings);
+        }
+
+        private static List<String> extractTimeZoneIds(List<TimeZoneMapping> timeZoneMappings) {
+            final List<String> zoneIds = new ArrayList<>(timeZoneMappings.size());
+            for (TimeZoneMapping timeZoneMapping : timeZoneMappings) {
+                zoneIds.add(timeZoneMapping.timeZoneId);
+            }
+            return Collections.unmodifiableList(zoneIds);
         }
     }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java
index 008943c..12d054e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java
@@ -126,10 +126,13 @@
             return;
         }
 
-        final List<Long> devicesHiSyncIds = new ArrayList<>();
         final List<BluetoothDevice> devices = hapProfile.getConnectableDevices();
-
         for (BluetoothDevice device : devices) {
+            // Only add master HearingAid device, ignore sub
+            if (mCachedBluetoothDeviceManager.isSubDevice(device)) {
+                Log.w(TAG, "Sub hearingAid device: " + device.getName());
+                continue;
+            }
             final CachedBluetoothDevice cachedDevice =
                     mCachedBluetoothDeviceManager.findDevice(device);
 
@@ -142,13 +145,8 @@
                     + ", is connected : " + cachedDevice.isConnected()
                     + ", is preferred : " + hapProfile.isPreferred(device));
 
-            final long hiSyncId = hapProfile.getHiSyncId(device);
-
-            // device with same hiSyncId should not be shown in the UI.
-            // So do not add it into connectedDevices.
-            if (!devicesHiSyncIds.contains(hiSyncId) && hapProfile.isPreferred(device)
+            if (hapProfile.isPreferred(device)
                     && BluetoothDevice.BOND_BONDED == cachedDevice.getBondState()) {
-                devicesHiSyncIds.add(hiSyncId);
                 addMediaDevice(cachedDevice);
             }
         }
@@ -284,9 +282,8 @@
                 + activeDevice + ", profile : " + bluetoothProfile);
 
         if (BluetoothProfile.HEARING_AID == bluetoothProfile) {
-            if (activeDevice != null) {
-                dispatchConnectedDeviceChanged(MediaDeviceUtils.getId(activeDevice));
-            }
+            dispatchConnectedDeviceChanged(activeDevice == null
+                    ? PhoneMediaDevice.ID : MediaDeviceUtils.getId(activeDevice));
         } else if (BluetoothProfile.A2DP == bluetoothProfile) {
             // When active device change to Hearing Aid,
             // BluetoothEventManager also send onActiveDeviceChanged() to notify that active device
@@ -304,12 +301,16 @@
     private MediaDevice findActiveHearingAidDevice() {
         final HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
 
-        if (hearingAidProfile != null) {
-            final List<BluetoothDevice> activeDevices = hearingAidProfile.getActiveDevices();
-            for (BluetoothDevice btDevice : activeDevices) {
-                if (btDevice != null) {
-                    return findMediaDevice(MediaDeviceUtils.getId(btDevice));
-                }
+        if (hearingAidProfile == null) {
+            Log.e(TAG, "findActiveHearingAidDevice: hearingAidProfile == null");
+            return null;
+        }
+        final List<BluetoothDevice> activeDevices = hearingAidProfile.getActiveDevices();
+        for (BluetoothDevice btDevice : activeDevices) {
+            final MediaDevice mediaDevice =
+                    findMediaDevice(Long.toString(hearingAidProfile.getHiSyncId(btDevice)));
+            if (mediaDevice != null) {
+                return mediaDevice;
             }
         }
         return null;
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDeviceUtils.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDeviceUtils.java
index f181150..4b8e706 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDeviceUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDeviceUtils.java
@@ -32,6 +32,9 @@
      * @return CachedBluetoothDevice address
      */
     public static String getId(CachedBluetoothDevice cachedDevice) {
+        if (cachedDevice.isHearingAidDevice()) {
+            return Long.toString(cachedDevice.getHiSyncId());
+        }
         return cachedDevice.getAddress();
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/LongPressWifiEntryPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/LongPressWifiEntryPreference.java
new file mode 100644
index 0000000..503d60c
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/LongPressWifiEntryPreference.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 com.android.settingslib.wifi;
+
+import android.content.Context;
+
+import androidx.fragment.app.Fragment;
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.wifitrackerlib.WifiEntry;
+
+/**
+ * WifiEntryPreference that can be long pressed.
+ */
+public class LongPressWifiEntryPreference extends WifiEntryPreference {
+
+    private final Fragment mFragment;
+
+    public LongPressWifiEntryPreference(Context context, WifiEntry wifiEntry, Fragment fragment) {
+        super(context, wifiEntry);
+        mFragment = fragment;
+    }
+
+    @Override
+    public void onBindViewHolder(final PreferenceViewHolder view) {
+        super.onBindViewHolder(view);
+        if (mFragment != null) {
+            view.itemView.setOnCreateContextMenuListener(mFragment);
+            view.itemView.setTag(this);
+            view.itemView.setLongClickable(true);
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java
new file mode 100644
index 0000000..22f47f1
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java
@@ -0,0 +1,238 @@
+/*
+ * 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.wifi;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.StateListDrawable;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.ImageView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.settingslib.R;
+import com.android.settingslib.Utils;
+import com.android.wifitrackerlib.WifiEntry;
+
+/**
+ * Preference to display a WifiEntry in a wifi picker.
+ */
+public class WifiEntryPreference extends Preference implements WifiEntry.WifiEntryCallback {
+
+    private static final int[] STATE_SECURED = {
+            R.attr.state_encrypted
+    };
+
+    private static final int[] STATE_METERED = {
+            R.attr.state_metered
+    };
+
+    private static final int[] FRICTION_ATTRS = {
+            R.attr.wifi_friction
+    };
+
+    // These values must be kept within [WifiEntry.WIFI_LEVEL_MIN, WifiEntry.WIFI_LEVEL_MAX]
+    private static final int[] WIFI_CONNECTION_STRENGTH = {
+            R.string.accessibility_no_wifi,
+            R.string.accessibility_wifi_one_bar,
+            R.string.accessibility_wifi_two_bars,
+            R.string.accessibility_wifi_three_bars,
+            R.string.accessibility_wifi_signal_full
+    };
+
+    // StateListDrawable to display secured lock / metered "$" icon
+    @Nullable private final StateListDrawable mFrictionSld;
+    private final IconInjector mIconInjector;
+    private WifiEntry mWifiEntry;
+    private int mLevel = -1;
+    private CharSequence mContentDescription;
+
+    public WifiEntryPreference(@NonNull Context context, @NonNull WifiEntry wifiEntry) {
+        this(context, wifiEntry, new IconInjector(context));
+    }
+
+    @VisibleForTesting
+    WifiEntryPreference(@NonNull Context context, @NonNull WifiEntry wifiEntry,
+            @NonNull IconInjector iconInjector) {
+        super(context);
+
+        setLayoutResource(R.layout.preference_access_point);
+        setWidgetLayoutResource(R.layout.access_point_friction_widget);
+        mFrictionSld = getFrictionStateListDrawable();
+        mWifiEntry = wifiEntry;
+        mWifiEntry.setListener(this);
+        mIconInjector = iconInjector;
+        refresh();
+    }
+
+    public WifiEntry getWifiEntry() {
+        return mWifiEntry;
+    }
+
+    @Override
+    public void onBindViewHolder(final PreferenceViewHolder view) {
+        super.onBindViewHolder(view);
+        final Drawable drawable = getIcon();
+        if (drawable != null) {
+            drawable.setLevel(mLevel);
+        }
+
+        view.itemView.setContentDescription(mContentDescription);
+
+        final ImageView frictionImageView = (ImageView) view.findViewById(R.id.friction_icon);
+        bindFrictionImage(frictionImageView);
+
+        // Turn off divider
+        view.findViewById(R.id.two_target_divider).setVisibility(View.INVISIBLE);
+    }
+
+    /**
+     * Updates the title and summary; may indirectly call notifyChanged().
+     */
+    public void refresh() {
+        setTitle(mWifiEntry.getTitle());
+        final int level = mWifiEntry.getLevel();
+        if (level != mLevel) {
+            mLevel = level;
+            updateIcon(mLevel);
+            notifyChanged();
+        }
+
+        setSummary(mWifiEntry.getSummary());
+        mContentDescription = buildContentDescription();
+    }
+
+    /**
+     * Indicates the state of the WifiEntry has changed and clients may retrieve updates through
+     * the WifiEntry getter methods.
+     */
+    public void onUpdated() {
+        // TODO(b/70983952): Fill this method in
+        refresh();
+    }
+
+    /**
+     * Result of the connect request indicated by the WifiEntry.CONNECT_STATUS constants.
+     */
+    public void onConnectResult(int status) {
+        // TODO(b/70983952): Fill this method in
+    }
+
+    /**
+     * Result of the disconnect request indicated by the WifiEntry.DISCONNECT_STATUS constants.
+     */
+    public void onDisconnectResult(int status) {
+        // TODO(b/70983952): Fill this method in
+    }
+
+    /**
+     * Result of the forget request indicated by the WifiEntry.FORGET_STATUS constants.
+     */
+    public void onForgetResult(int status) {
+        // TODO(b/70983952): Fill this method in
+    }
+
+    private void updateIcon(int level) {
+        if (level == -1) {
+            setIcon(null);
+            return;
+        }
+
+        final Drawable drawable = mIconInjector.getIcon(level);
+        if (drawable != null) {
+            drawable.setTintList(Utils.getColorAttr(getContext(),
+                    android.R.attr.colorControlNormal));
+            setIcon(drawable);
+        } else {
+            setIcon(null);
+        }
+    }
+
+    @Nullable
+    private StateListDrawable getFrictionStateListDrawable() {
+        TypedArray frictionSld;
+        try {
+            frictionSld = getContext().getTheme().obtainStyledAttributes(FRICTION_ATTRS);
+        } catch (Resources.NotFoundException e) {
+            // Fallback for platforms that do not need friction icon resources.
+            frictionSld = null;
+        }
+        return frictionSld != null ? (StateListDrawable) frictionSld.getDrawable(0) : null;
+    }
+
+    /**
+     * Binds the friction icon drawable using a StateListDrawable.
+     *
+     * <p>Friction icons will be rebound when notifyChange() is called, and therefore
+     * do not need to be managed in refresh()</p>.
+     */
+    private void bindFrictionImage(ImageView frictionImageView) {
+        if (frictionImageView == null || mFrictionSld == null) {
+            return;
+        }
+        if ((mWifiEntry.getSecurity() != WifiEntry.SECURITY_NONE)
+                && (mWifiEntry.getSecurity() != WifiEntry.SECURITY_OWE)
+                && (mWifiEntry.getSecurity() != WifiEntry.SECURITY_OWE_TRANSITION)) {
+            mFrictionSld.setState(STATE_SECURED);
+        } else if (mWifiEntry.isMetered()) {
+            mFrictionSld.setState(STATE_METERED);
+        }
+        frictionImageView.setImageDrawable(mFrictionSld.getCurrent());
+    }
+
+    /**
+     * Helper method to generate content description string.
+     */
+    @VisibleForTesting
+    CharSequence buildContentDescription() {
+        final Context context = getContext();
+
+        CharSequence contentDescription = getTitle();
+        final CharSequence summary = getSummary();
+        if (!TextUtils.isEmpty(summary)) {
+            contentDescription = TextUtils.concat(contentDescription, ",", summary);
+        }
+        int level = mWifiEntry.getLevel();
+        if (level >= 0 && level < WIFI_CONNECTION_STRENGTH.length) {
+            contentDescription = TextUtils.concat(contentDescription, ",",
+                    context.getString(WIFI_CONNECTION_STRENGTH[level]));
+        }
+        return TextUtils.concat(contentDescription, ",",
+                mWifiEntry.getSecurity() == WifiEntry.SECURITY_NONE
+                        ? context.getString(R.string.accessibility_wifi_security_type_none)
+                        : context.getString(R.string.accessibility_wifi_security_type_secured));
+    }
+
+
+    static class IconInjector {
+        private final Context mContext;
+
+        IconInjector(Context context) {
+            mContext = context;
+        }
+
+        public Drawable getIcon(int level) {
+            return mContext.getDrawable(Utils.getWifiIconResource(level));
+        }
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaManagerTest.java
index 030bab6..f27cef9 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaManagerTest.java
@@ -428,20 +428,21 @@
 
     @Test
     public void onActiveDeviceChanged_hearingAidDeviceIsActive_returnHearingAidDeviceId() {
+        final Long hiSyncId = Integer.toUnsignedLong(12345);
         final BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class);
         final List<BluetoothDevice> devices = new ArrayList<>();
         devices.add(bluetoothDevice);
         final BluetoothMediaDevice bluetoothMediaDevice = mock(BluetoothMediaDevice.class);
         mMediaManager.mMediaDevices.add(bluetoothMediaDevice);
 
-        when(bluetoothDevice.getAddress()).thenReturn(TEST_ADDRESS);
+        when(mHapProfile.getHiSyncId(bluetoothDevice)).thenReturn(hiSyncId);
         when(mHapProfile.getActiveDevices()).thenReturn(devices);
-        when(bluetoothMediaDevice.getId()).thenReturn(TEST_ADDRESS);
+        when(bluetoothMediaDevice.getId()).thenReturn(Long.toString(hiSyncId));
 
         mMediaManager.registerCallback(mCallback);
         mMediaManager.onActiveDeviceChanged(null, BluetoothProfile.A2DP);
 
-        verify(mCallback).onConnectedDeviceChanged(TEST_ADDRESS);
+        verify(mCallback).onConnectedDeviceChanged(Long.toString(hiSyncId));
     }
 
     @Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java
new file mode 100644
index 0000000..752a549
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java
@@ -0,0 +1,150 @@
+/*
+ * 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.wifi;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+
+import com.android.wifitrackerlib.WifiEntry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(RobolectricTestRunner.class)
+public class WifiEntryPreferenceTest {
+
+    private Context mContext;
+
+    @Mock
+    private WifiEntry mMockWifiEntry;
+    @Mock
+    private WifiEntryPreference.IconInjector mMockIconInjector;
+
+    @Mock
+    private Drawable mMockDrawable0;
+    @Mock
+    private Drawable mMockDrawable1;
+    @Mock
+    private Drawable mMockDrawable2;
+    @Mock
+    private Drawable mMockDrawable3;
+    @Mock
+    private Drawable mMockDrawable4;
+
+    private static final String MOCK_TITLE = "title";
+    private static final String MOCK_SUMMARY = "summary";
+
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+
+        MockitoAnnotations.initMocks(this);
+
+        when(mMockWifiEntry.getTitle()).thenReturn(MOCK_TITLE);
+        when(mMockWifiEntry.getSummary()).thenReturn(MOCK_SUMMARY);
+
+        when(mMockIconInjector.getIcon(0)).thenReturn(mMockDrawable0);
+        when(mMockIconInjector.getIcon(1)).thenReturn(mMockDrawable1);
+        when(mMockIconInjector.getIcon(2)).thenReturn(mMockDrawable2);
+        when(mMockIconInjector.getIcon(3)).thenReturn(mMockDrawable3);
+        when(mMockIconInjector.getIcon(4)).thenReturn(mMockDrawable4);
+    }
+
+    @Test
+    public void constructor_shouldSetWifiEntryTitleAndSummary() {
+        final WifiEntryPreference pref =
+                new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector);
+
+        assertThat(pref.getTitle()).isEqualTo(MOCK_TITLE);
+        assertThat(pref.getSummary()).isEqualTo(MOCK_SUMMARY);
+    }
+
+    @Test
+    public void constructor_shouldSetIcon() {
+        when(mMockWifiEntry.getLevel()).thenReturn(0);
+
+        final WifiEntryPreference pref =
+                new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector);
+
+        assertThat(pref.getIcon()).isEqualTo(mMockDrawable0);
+    }
+
+    @Test
+    public void titleChanged_refresh_shouldUpdateTitle() {
+        final WifiEntryPreference pref =
+                new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector);
+        final String updatedTitle = "updated title";
+        when(mMockWifiEntry.getTitle()).thenReturn(updatedTitle);
+
+        pref.refresh();
+
+        assertThat(pref.getTitle()).isEqualTo(updatedTitle);
+    }
+
+    @Test
+    public void summaryChanged_refresh_shouldUpdateSummary() {
+        final WifiEntryPreference pref =
+                new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector);
+        final String updatedSummary = "updated summary";
+        when(mMockWifiEntry.getSummary()).thenReturn(updatedSummary);
+
+        pref.refresh();
+
+        assertThat(pref.getSummary()).isEqualTo(updatedSummary);
+    }
+
+    @Test
+    public void levelChanged_refresh_shouldUpdateLevelIcon() {
+        final List<Drawable> iconList = new ArrayList<>();
+        final WifiEntryPreference pref =
+                new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector);
+
+        when(mMockWifiEntry.getLevel()).thenReturn(0);
+        pref.refresh();
+        iconList.add(pref.getIcon());
+        when(mMockWifiEntry.getLevel()).thenReturn(1);
+        pref.refresh();
+        iconList.add(pref.getIcon());
+        when(mMockWifiEntry.getLevel()).thenReturn(2);
+        pref.refresh();
+        iconList.add(pref.getIcon());
+        when(mMockWifiEntry.getLevel()).thenReturn(3);
+        pref.refresh();
+        iconList.add(pref.getIcon());
+        when(mMockWifiEntry.getLevel()).thenReturn(4);
+        pref.refresh();
+        iconList.add(pref.getIcon());
+        when(mMockWifiEntry.getLevel()).thenReturn(-1);
+        pref.refresh();
+        iconList.add(pref.getIcon());
+
+        assertThat(iconList).containsExactly(mMockDrawable0, mMockDrawable1,
+                mMockDrawable2, mMockDrawable3, mMockDrawable4, null);
+    }
+}
diff --git a/packages/SettingsProvider/Android.bp b/packages/SettingsProvider/Android.bp
index e54b847..681b494 100644
--- a/packages/SettingsProvider/Android.bp
+++ b/packages/SettingsProvider/Android.bp
@@ -11,7 +11,7 @@
     ],
     static_libs: [
         "junit",
-        "SettingsLib",
+        "SettingsLibDisplayDensityUtils",
     ],
     platform_apis: true,
     certificate: "platform",
@@ -24,13 +24,17 @@
     // because this test is not an instrumentation test. (because the target runs in the system process.)
     srcs: [
         "test/**/*.java",
+        "src/android/provider/settings/backup/*",
+        "src/android/provider/settings/validators/*",
         "src/com/android/providers/settings/SettingsBackupAgent.java",
         "src/com/android/providers/settings/SettingsState.java",
         "src/com/android/providers/settings/SettingsHelper.java",
     ],
     static_libs: [
         "androidx.test.rules",
-        "SettingsLib",
+        "SettingsLibDisplayDensityUtils",
+        "platform-test-annotations",
+        "truth-prebuilt",
     ],
     libs: [
         "android.test.base",
diff --git a/packages/SettingsProvider/TEST_MAPPING b/packages/SettingsProvider/TEST_MAPPING
new file mode 100644
index 0000000..890510f
--- /dev/null
+++ b/packages/SettingsProvider/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+    "presubmit": [
+        {
+            "name": "SettingsProviderTest"
+        },
+        {
+            "name": "CtsProviderTestCases",
+            "options": [
+                {
+                    "include-filter": "android.provider.cts.settings."
+                }
+            ]
+        }
+    ]
+}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
new file mode 100644
index 0000000..0c49f63
--- /dev/null
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
@@ -0,0 +1,73 @@
+/*
+ * 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.backup;
+
+import android.provider.Settings;
+
+/** Information related to the backup of Global settings */
+public class GlobalSettings {
+
+    /**
+     * These keys may be mentioned in the SETTINGS_TO_BACKUP arrays in SystemSettings
+     * and SecureSettings as well.  This is because those tables drive both backup and
+     * restore, and restore needs to properly whitelist keys that used to live
+     * in those namespaces.
+     *
+     * NOTE: Settings are backed up and restored in the order they appear
+     *       in this array. If you have one setting depending on another,
+     *       make sure that they are ordered appropriately.
+     *
+     * NOTE: This table should only be used for settings which should be restored
+     *       between different types of devices
+     *       {@see #Settings.Secure.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP}
+     *
+     * NOTE: All settings which are backed up should have a corresponding validator.
+     */
+    public static final String[] SETTINGS_TO_BACKUP = {
+        Settings.Global.APPLY_RAMPING_RINGER,
+        Settings.Global.BUGREPORT_IN_POWER_MENU,
+        Settings.Global.STAY_ON_WHILE_PLUGGED_IN,
+        Settings.Global.APP_AUTO_RESTRICTION_ENABLED,
+        Settings.Global.AUTO_TIME,
+        Settings.Global.AUTO_TIME_ZONE,
+        Settings.Global.POWER_SOUNDS_ENABLED,
+        Settings.Global.DOCK_SOUNDS_ENABLED,
+        Settings.Global.CHARGING_SOUNDS_ENABLED,
+        Settings.Global.USB_MASS_STORAGE_ENABLED,
+        Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED,
+        Settings.Global.WIFI_WAKEUP_ENABLED,
+        Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
+        Settings.Global.USE_OPEN_WIFI_PACKAGE,
+        Settings.Global.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED,
+        Settings.Global.EMERGENCY_TONE,
+        Settings.Global.CALL_AUTO_RETRY,
+        Settings.Global.DOCK_AUDIO_MEDIA_ENABLED,
+        Settings.Global.ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS,
+        Settings.Global.ENCODED_SURROUND_OUTPUT,
+        Settings.Global.ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS,
+        Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL,
+        Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED,
+        Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL,
+        Settings.Global.BLUETOOTH_ON,
+        Settings.Global.PRIVATE_DNS_MODE,
+        Settings.Global.PRIVATE_DNS_SPECIFIER,
+        Settings.Global.SOFT_AP_TIMEOUT_ENABLED,
+        Settings.Global.ZEN_DURATION,
+        Settings.Global.CHARGING_VIBRATION_ENABLED,
+        Settings.Global.AWARE_ALLOWED,
+    };
+}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
new file mode 100644
index 0000000..8c2e431
--- /dev/null
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -0,0 +1,166 @@
+/*
+ * 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.backup;
+
+import android.annotation.UnsupportedAppUsage;
+import android.provider.Settings;
+
+/** Information relating to the Secure settings which should be backed up */
+public class SecureSettings {
+
+    /**
+     * NOTE: Settings are backed up and restored in the order they appear
+     *       in this array. If you have one setting depending on another,
+     *       make sure that they are ordered appropriately.
+     */
+    @UnsupportedAppUsage
+    public static final String[] SETTINGS_TO_BACKUP = {
+        Settings.Secure.BUGREPORT_IN_POWER_MENU,                            // moved to global
+        Settings.Secure.ALLOW_MOCK_LOCATION,
+        Settings.Secure.USB_MASS_STORAGE_ENABLED,                           // moved to global
+        Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED,
+        Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER,
+        Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
+        Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
+        Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED,
+        Settings.Secure.AUTOFILL_SERVICE,
+        Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
+        Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+        Settings.Secure.ENABLED_VR_LISTENERS,
+        Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
+        Settings.Secure.TOUCH_EXPLORATION_ENABLED,
+        Settings.Secure.ACCESSIBILITY_ENABLED,
+        Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
+        Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT,
+        Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+        Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED,
+        Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN,
+        Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED,
+        Settings.Secure.ACCESSIBILITY_CAPTIONING_PRESET,
+        Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED,
+        Settings.Secure.ACCESSIBILITY_CAPTIONING_LOCALE,
+        Settings.Secure.ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR,
+        Settings.Secure.ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR,
+        Settings.Secure.ACCESSIBILITY_CAPTIONING_EDGE_TYPE,
+        Settings.Secure.ACCESSIBILITY_CAPTIONING_EDGE_COLOR,
+        Settings.Secure.ACCESSIBILITY_CAPTIONING_TYPEFACE,
+        Settings.Secure.ACCESSIBILITY_CAPTIONING_FONT_SCALE,
+        Settings.Secure.ACCESSIBILITY_CAPTIONING_WINDOW_COLOR,
+        Settings.Secure.TTS_DEFAULT_RATE,
+        Settings.Secure.TTS_DEFAULT_PITCH,
+        Settings.Secure.TTS_DEFAULT_SYNTH,
+        Settings.Secure.TTS_ENABLED_PLUGINS,
+        Settings.Secure.TTS_DEFAULT_LOCALE,
+        Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD,
+        Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,            // moved to global
+        Settings.Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,               // moved to global
+        Settings.Secure.WIFI_NUM_OPEN_NETWORKS_KEPT,                        // moved to global
+        Settings.Secure.MOUNT_PLAY_NOTIFICATION_SND,
+        Settings.Secure.MOUNT_UMS_AUTOSTART,
+        Settings.Secure.MOUNT_UMS_PROMPT,
+        Settings.Secure.MOUNT_UMS_NOTIFY_ENABLED,
+        Settings.Secure.DOUBLE_TAP_TO_WAKE,
+        Settings.Secure.WAKE_GESTURE_ENABLED,
+        Settings.Secure.LONG_PRESS_TIMEOUT,
+        Settings.Secure.CAMERA_GESTURE_DISABLED,
+        Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED,
+        Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY,
+        Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
+        Settings.Secure.PREFERRED_TTY_MODE,
+        Settings.Secure.ENHANCED_VOICE_PRIVACY_ENABLED,
+        Settings.Secure.TTY_MODE_ENABLED,
+        Settings.Secure.RTT_CALLING_MODE,
+        Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
+        Settings.Secure.NIGHT_DISPLAY_CUSTOM_START_TIME,
+        Settings.Secure.NIGHT_DISPLAY_CUSTOM_END_TIME,
+        Settings.Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE,
+        Settings.Secure.NIGHT_DISPLAY_AUTO_MODE,
+        Settings.Secure.DISPLAY_WHITE_BALANCE_ENABLED,
+        Settings.Secure.SYNC_PARENT_SOUNDS,
+        Settings.Secure.CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED,
+        Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED,
+        Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED,
+        Settings.Secure.QS_TILES,
+        Settings.Secure.DOZE_ENABLED,
+        Settings.Secure.DOZE_ALWAYS_ON,
+        Settings.Secure.DOZE_PICK_UP_GESTURE,
+        Settings.Secure.DOZE_DOUBLE_TAP_GESTURE,
+        Settings.Secure.DOZE_TAP_SCREEN_GESTURE,
+        Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE,
+        Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE,
+        Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT,
+        Settings.Secure.AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN,
+        Settings.Secure.FACE_UNLOCK_KEYGUARD_ENABLED,
+        Settings.Secure.SHOW_MEDIA_WHEN_BYPASSING,
+        Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD,
+        Settings.Secure.FACE_UNLOCK_APP_ENABLED,
+        Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION,
+        Settings.Secure.ASSIST_GESTURE_ENABLED,
+        Settings.Secure.ASSIST_GESTURE_SILENCE_ALERTS_ENABLED,
+        Settings.Secure.ASSIST_GESTURE_WAKE_ENABLED,
+        Settings.Secure.VR_DISPLAY_MODE,
+        Settings.Secure.NOTIFICATION_BADGING,
+        Settings.Secure.NOTIFICATION_BUBBLES,
+        Settings.Secure.NOTIFICATION_DISMISS_RTL,
+        Settings.Secure.QS_AUTO_ADDED_TILES,
+        Settings.Secure.SCREENSAVER_ENABLED,
+        Settings.Secure.SCREENSAVER_COMPONENTS,
+        Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
+        Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
+        Settings.Secure.LOCKDOWN_IN_POWER_MENU,
+        Settings.Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
+        Settings.Secure.VOLUME_HUSH_GESTURE,
+        Settings.Secure.MANUAL_RINGER_TOGGLE_COUNT,
+        Settings.Secure.HUSH_GESTURE_USED,
+        Settings.Secure.IN_CALL_NOTIFICATION_ENABLED,
+        Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
+        Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE,
+        Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
+        Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS,
+        Settings.Secure.SHOW_NOTIFICATION_SNOOZE,
+        Settings.Secure.ZEN_DURATION,
+        Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION,
+        Settings.Secure.SHOW_ZEN_SETTINGS_SUGGESTION,
+        Settings.Secure.ZEN_SETTINGS_UPDATED,
+        Settings.Secure.ZEN_SETTINGS_SUGGESTION_VIEWED,
+        Settings.Secure.CHARGING_SOUNDS_ENABLED,
+        Settings.Secure.CHARGING_VIBRATION_ENABLED,
+        Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS,
+        Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS,
+        Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL,
+        Settings.Secure.TRUST_AGENTS_EXTEND_UNLOCK,
+        Settings.Secure.UI_NIGHT_MODE,
+        Settings.Secure.LOCK_SCREEN_WHEN_TRUST_LOST,
+        Settings.Secure.SKIP_GESTURE,
+        Settings.Secure.SKIP_DIRECTION,
+        Settings.Secure.SILENCE_GESTURE,
+        Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
+        Settings.Secure.NAVIGATION_MODE,
+        Settings.Secure.AWARE_ENABLED,
+        Settings.Secure.SKIP_GESTURE_COUNT,
+        Settings.Secure.SKIP_TOUCH_COUNT,
+        Settings.Secure.SILENCE_ALARMS_GESTURE_COUNT,
+        Settings.Secure.SILENCE_CALL_GESTURE_COUNT,
+        Settings.Secure.SILENCE_TIMER_GESTURE_COUNT,
+        Settings.Secure.SILENCE_ALARMS_TOUCH_COUNT,
+        Settings.Secure.SILENCE_CALL_TOUCH_COUNT,
+        Settings.Secure.SILENCE_TIMER_TOUCH_COUNT,
+        Settings.Secure.DARK_MODE_DIALOG_SEEN,
+        Settings.Secure.GLOBAL_ACTIONS_PANEL_ENABLED,
+        Settings.Secure.AWARE_LOCK_ENABLED
+    };
+}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
new file mode 100644
index 0000000..89b19de
--- /dev/null
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.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 android.provider.settings.backup;
+
+import android.annotation.UnsupportedAppUsage;
+import android.provider.Settings;
+
+/** Information about the system settings to back up */
+public class SystemSettings {
+
+    /**
+     * Settings to backup.
+     *
+     * NOTE: Settings are backed up and restored in the order they appear
+     *       in this array. If you have one setting depending on another,
+     *       make sure that they are ordered appropriately.
+     */
+    @UnsupportedAppUsage
+    public static final String[] SETTINGS_TO_BACKUP = {
+        Settings.System.STAY_ON_WHILE_PLUGGED_IN,   // moved to global
+        Settings.System.WIFI_USE_STATIC_IP,
+        Settings.System.WIFI_STATIC_IP,
+        Settings.System.WIFI_STATIC_GATEWAY,
+        Settings.System.WIFI_STATIC_NETMASK,
+        Settings.System.WIFI_STATIC_DNS1,
+        Settings.System.WIFI_STATIC_DNS2,
+        Settings.System.BLUETOOTH_DISCOVERABILITY,
+        Settings.System.BLUETOOTH_DISCOVERABILITY_TIMEOUT,
+        Settings.System.FONT_SCALE,
+        Settings.System.DIM_SCREEN,
+        Settings.System.SCREEN_OFF_TIMEOUT,
+        Settings.System.SCREEN_BRIGHTNESS_MODE,
+        Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ,
+        Settings.System.SCREEN_BRIGHTNESS_FOR_VR,
+        Settings.System.ADAPTIVE_SLEEP,
+        Settings.System.VIBRATE_INPUT_DEVICES,
+        Settings.System.MODE_RINGER_STREAMS_AFFECTED,
+        Settings.System.TEXT_AUTO_REPLACE,
+        Settings.System.TEXT_AUTO_CAPS,
+        Settings.System.TEXT_AUTO_PUNCTUATE,
+        Settings.System.TEXT_SHOW_PASSWORD,
+        Settings.System.AUTO_TIME,                  // moved to global
+        Settings.System.AUTO_TIME_ZONE,             // moved to global
+        Settings.System.TIME_12_24,
+        Settings.System.DATE_FORMAT,
+        Settings.System.DTMF_TONE_WHEN_DIALING,
+        Settings.System.DTMF_TONE_TYPE_WHEN_DIALING,
+        Settings.System.HEARING_AID,
+        Settings.System.TTY_MODE,
+        Settings.System.MASTER_MONO,
+        Settings.System.MASTER_BALANCE,
+        Settings.System.SOUND_EFFECTS_ENABLED,
+        Settings.System.HAPTIC_FEEDBACK_ENABLED,
+        Settings.System.POWER_SOUNDS_ENABLED,       // moved to global
+        Settings.System.DOCK_SOUNDS_ENABLED,        // moved to global
+        Settings.System.LOCKSCREEN_SOUNDS_ENABLED,
+        Settings.System.SHOW_WEB_SUGGESTIONS,
+        Settings.System.SIP_CALL_OPTIONS,
+        Settings.System.SIP_RECEIVE_CALLS,
+        Settings.System.POINTER_SPEED,
+        Settings.System.VIBRATE_WHEN_RINGING,
+        Settings.System.RINGTONE,
+        Settings.System.LOCK_TO_APP_ENABLED,
+        Settings.System.NOTIFICATION_SOUND,
+        Settings.System.ACCELEROMETER_ROTATION,
+        Settings.System.SHOW_BATTERY_PERCENT,
+        Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+        Settings.System.RING_VIBRATION_INTENSITY,
+        Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+        Settings.System.DISPLAY_COLOR_MODE,
+        Settings.System.ALARM_ALERT,
+        Settings.System.NOTIFICATION_LIGHT_PULSE,
+    };
+}
diff --git a/core/java/android/provider/settings/validators/ComponentNameListValidator.java b/packages/SettingsProvider/src/android/provider/settings/validators/ComponentNameListValidator.java
similarity index 100%
rename from core/java/android/provider/settings/validators/ComponentNameListValidator.java
rename to packages/SettingsProvider/src/android/provider/settings/validators/ComponentNameListValidator.java
diff --git a/core/java/android/provider/settings/validators/DiscreteValueValidator.java b/packages/SettingsProvider/src/android/provider/settings/validators/DiscreteValueValidator.java
similarity index 100%
rename from core/java/android/provider/settings/validators/DiscreteValueValidator.java
rename to packages/SettingsProvider/src/android/provider/settings/validators/DiscreteValueValidator.java
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
new file mode 100644
index 0000000..9be636d
--- /dev/null
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.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.provider.settings.validators;
+
+import static android.provider.settings.validators.SettingsValidators.ANY_INTEGER_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.ANY_STRING_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.BOOLEAN_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.PACKAGE_NAME_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.PERCENTAGE_INTEGER_VALIDATOR;
+
+import android.media.AudioFormat;
+import android.os.BatteryManager;
+import android.provider.Settings.Global;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+
+import java.util.Map;
+
+/**
+ * Validators for Global settings
+ */
+public class GlobalSettingsValidators {
+    /**
+     * All settings in {@link Global.SETTINGS_TO_BACKUP} array *must* have a non-null validator,
+     * otherwise they won't be restored.
+     */
+    public static final Map<String, Validator> VALIDATORS = new ArrayMap<>();
+
+    static {
+        VALIDATORS.put(Global.APPLY_RAMPING_RINGER, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.BUGREPORT_IN_POWER_MENU, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(
+                Global.STAY_ON_WHILE_PLUGGED_IN,
+                value -> {
+                    try {
+                        int val = Integer.parseInt(value);
+                        return (val == 0)
+                                || (val == BatteryManager.BATTERY_PLUGGED_AC)
+                                || (val == BatteryManager.BATTERY_PLUGGED_USB)
+                                || (val == BatteryManager.BATTERY_PLUGGED_WIRELESS)
+                                || (val
+                                        == (BatteryManager.BATTERY_PLUGGED_AC
+                                                | BatteryManager.BATTERY_PLUGGED_USB))
+                                || (val
+                                        == (BatteryManager.BATTERY_PLUGGED_AC
+                                                | BatteryManager.BATTERY_PLUGGED_WIRELESS))
+                                || (val
+                                        == (BatteryManager.BATTERY_PLUGGED_USB
+                                                | BatteryManager.BATTERY_PLUGGED_WIRELESS))
+                                || (val
+                                        == (BatteryManager.BATTERY_PLUGGED_AC
+                                                | BatteryManager.BATTERY_PLUGGED_USB
+                                                | BatteryManager.BATTERY_PLUGGED_WIRELESS));
+                    } catch (NumberFormatException e) {
+                        return false;
+                    }
+                });
+        VALIDATORS.put(Global.AUTO_TIME, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.AUTO_TIME_ZONE, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.POWER_SOUNDS_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.DOCK_SOUNDS_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.CHARGING_SOUNDS_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.USB_MASS_STORAGE_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(
+                Global.NETWORK_RECOMMENDATIONS_ENABLED,
+                new DiscreteValueValidator(new String[] {"-1", "0", "1"}));
+        VALIDATORS.put(Global.WIFI_WAKEUP_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(
+                Global.USE_OPEN_WIFI_PACKAGE,
+                value -> (value == null) || PACKAGE_NAME_VALIDATOR.validate(value));
+        VALIDATORS.put(Global.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED, ANY_STRING_VALIDATOR);
+        VALIDATORS.put(
+                Global.EMERGENCY_TONE, new DiscreteValueValidator(new String[] {"0", "1", "2"}));
+        VALIDATORS.put(Global.CALL_AUTO_RETRY, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.DOCK_AUDIO_MEDIA_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(
+                Global.ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS,
+                new DiscreteValueValidator(new String[] {"0", "1"}));
+        VALIDATORS.put(
+                Global.ENCODED_SURROUND_OUTPUT,
+                new DiscreteValueValidator(new String[] {"0", "1", "2", "3"}));
+        VALIDATORS.put(
+                Global.ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS,
+                value -> {
+                    try {
+                        String[] surroundFormats = TextUtils.split(value, ",");
+                        for (String format : surroundFormats) {
+                            int audioFormat = Integer.valueOf(format);
+                            boolean isSurroundFormat = false;
+                            for (int sf : AudioFormat.SURROUND_SOUND_ENCODING) {
+                                if (sf == audioFormat) {
+                                    isSurroundFormat = true;
+                                    break;
+                                }
+                            }
+                            if (!isSurroundFormat) {
+                                return false;
+                            }
+                        }
+                        return true;
+                    } catch (NumberFormatException e) {
+                        return false;
+                    }
+                });
+        VALIDATORS.put(
+                Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL,
+                new InclusiveIntegerRangeValidator(0, 100));
+        VALIDATORS.put(
+                Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED,
+                new DiscreteValueValidator(new String[] {"0", "1"}));
+        VALIDATORS.put(Global.LOW_POWER_MODE_TRIGGER_LEVEL, PERCENTAGE_INTEGER_VALIDATOR);
+        VALIDATORS.put(Global.LOW_POWER_MODE_TRIGGER_LEVEL_MAX, PERCENTAGE_INTEGER_VALIDATOR);
+        VALIDATORS.put(
+                Global.AUTOMATIC_POWER_SAVE_MODE,
+                new DiscreteValueValidator(new String[] {"0", "1"}));
+        VALIDATORS.put(
+                Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, PERCENTAGE_INTEGER_VALIDATOR);
+        VALIDATORS.put(Global.BLUETOOTH_ON, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.PRIVATE_DNS_MODE, ANY_STRING_VALIDATOR);
+        VALIDATORS.put(Global.PRIVATE_DNS_SPECIFIER, ANY_STRING_VALIDATOR);
+        VALIDATORS.put(Global.SOFT_AP_TIMEOUT_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.WIFI_SCAN_THROTTLE_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.APP_AUTO_RESTRICTION_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.ZEN_DURATION, ANY_INTEGER_VALIDATOR);
+        VALIDATORS.put(Global.CHARGING_VIBRATION_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.REQUIRE_PASSWORD_TO_DECRYPT, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.DEVICE_DEMO_MODE, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.WIFI_PNO_FREQUENCY_CULLING_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.WIFI_PNO_RECENCY_SORTING_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.WIFI_LINK_PROBING_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.AWARE_ALLOWED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.POWER_BUTTON_LONG_PRESS, new InclusiveIntegerRangeValidator(0, 5));
+        VALIDATORS.put(
+                Global.POWER_BUTTON_VERY_LONG_PRESS, new InclusiveIntegerRangeValidator(0, 1));
+    }
+}
diff --git a/core/java/android/provider/settings/validators/InclusiveFloatRangeValidator.java b/packages/SettingsProvider/src/android/provider/settings/validators/InclusiveFloatRangeValidator.java
similarity index 89%
rename from core/java/android/provider/settings/validators/InclusiveFloatRangeValidator.java
rename to packages/SettingsProvider/src/android/provider/settings/validators/InclusiveFloatRangeValidator.java
index 38400ac..1a0b88c 100644
--- a/core/java/android/provider/settings/validators/InclusiveFloatRangeValidator.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/InclusiveFloatRangeValidator.java
@@ -23,11 +23,11 @@
  *
  * @hide
  */
-public final class InclusiveFloatRangeValidator implements Validator {
+final class InclusiveFloatRangeValidator implements Validator {
     private final float mMin;
     private final float mMax;
 
-    public InclusiveFloatRangeValidator(float min, float max) {
+    InclusiveFloatRangeValidator(float min, float max) {
         mMin = min;
         mMax = max;
     }
diff --git a/core/java/android/provider/settings/validators/InclusiveIntegerRangeValidator.java b/packages/SettingsProvider/src/android/provider/settings/validators/InclusiveIntegerRangeValidator.java
similarity index 89%
rename from core/java/android/provider/settings/validators/InclusiveIntegerRangeValidator.java
rename to packages/SettingsProvider/src/android/provider/settings/validators/InclusiveIntegerRangeValidator.java
index e53c252..f9f8ce8 100644
--- a/core/java/android/provider/settings/validators/InclusiveIntegerRangeValidator.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/InclusiveIntegerRangeValidator.java
@@ -23,11 +23,11 @@
  *
  * @hide
  */
-public final class InclusiveIntegerRangeValidator implements Validator {
+final class InclusiveIntegerRangeValidator implements Validator {
     private final int mMin;
     private final int mMax;
 
-    public InclusiveIntegerRangeValidator(int min, int max) {
+    InclusiveIntegerRangeValidator(int min, int max) {
         mMin = min;
         mMax = max;
     }
diff --git a/core/java/android/provider/settings/validators/ListValidator.java b/packages/SettingsProvider/src/android/provider/settings/validators/ListValidator.java
similarity index 100%
rename from core/java/android/provider/settings/validators/ListValidator.java
rename to packages/SettingsProvider/src/android/provider/settings/validators/ListValidator.java
diff --git a/core/java/android/provider/settings/validators/PackageNameListValidator.java b/packages/SettingsProvider/src/android/provider/settings/validators/PackageNameListValidator.java
similarity index 89%
rename from core/java/android/provider/settings/validators/PackageNameListValidator.java
rename to packages/SettingsProvider/src/android/provider/settings/validators/PackageNameListValidator.java
index bc7fc13..a883223 100644
--- a/core/java/android/provider/settings/validators/PackageNameListValidator.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/PackageNameListValidator.java
@@ -23,8 +23,8 @@
  *
  * @hide
  */
-public final class PackageNameListValidator extends ListValidator {
-    public PackageNameListValidator(String separator) {
+final class PackageNameListValidator extends ListValidator {
+    PackageNameListValidator(String separator) {
         super(separator);
     }
 
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
new file mode 100644
index 0000000..f160edc6
--- /dev/null
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -0,0 +1,231 @@
+/*
+ * 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.ANY_INTEGER_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.BOOLEAN_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.COLON_SEPARATED_COMPONENT_LIST_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.COLON_SEPARATED_PACKAGE_LIST_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.COMMA_SEPARATED_COMPONENT_LIST_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.COMPONENT_NAME_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.JSON_OBJECT_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.LOCALE_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.NON_NEGATIVE_INTEGER_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.NULLABLE_COMPONENT_NAME_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.PACKAGE_NAME_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.TILE_LIST_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.TTS_LIST_VALIDATOR;
+
+import android.provider.Settings.Secure;
+import android.util.ArrayMap;
+
+import java.util.Map;
+
+/**
+ * Validators for the Secure Settings.
+ */
+public class SecureSettingsValidators {
+    /**
+     * All settings in {@link Secure.SETTINGS_TO_BACKUP} and {@link
+     * Secure.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP} array *must* have a non-null validator, otherwise
+     * they won't be restored.
+     */
+    public static final Map<String, Validator> VALIDATORS = new ArrayMap<>();
+
+    static {
+        VALIDATORS.put(Secure.BUGREPORT_IN_POWER_MENU, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.ALLOW_MOCK_LOCATION, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.USB_MASS_STORAGE_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(
+                Secure.ACCESSIBILITY_DISPLAY_DALTONIZER,
+                new DiscreteValueValidator(new String[] {"-1", "0", "11", "12", "13"}));
+        VALIDATORS.put(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(
+                Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.AUTOFILL_SERVICE, NULLABLE_COMPONENT_NAME_VALIDATOR);
+        VALIDATORS.put(
+                Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
+                new InclusiveFloatRangeValidator(1.0f, Float.MAX_VALUE));
+        VALIDATORS.put(
+                Secure.ENABLED_ACCESSIBILITY_SERVICES, COLON_SEPARATED_COMPONENT_LIST_VALIDATOR);
+        VALIDATORS.put(Secure.ENABLED_VR_LISTENERS, COLON_SEPARATED_COMPONENT_LIST_VALIDATOR);
+        VALIDATORS.put(
+                Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
+                COLON_SEPARATED_COMPONENT_LIST_VALIDATOR);
+        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);
+        // 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_SHORTCUT_DIALOG_SHOWN, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.ACCESSIBILITY_SHORTCUT_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(
+                Secure.ACCESSIBILITY_CAPTIONING_PRESET,
+                new DiscreteValueValidator(new String[] {"-1", "0", "1", "2", "3", "4"}));
+        VALIDATORS.put(Secure.ACCESSIBILITY_CAPTIONING_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.ACCESSIBILITY_CAPTIONING_LOCALE, LOCALE_VALIDATOR);
+        VALIDATORS.put(Secure.ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR, ANY_INTEGER_VALIDATOR);
+        VALIDATORS.put(Secure.ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR, ANY_INTEGER_VALIDATOR);
+        VALIDATORS.put(
+                Secure.ACCESSIBILITY_CAPTIONING_EDGE_TYPE,
+                new DiscreteValueValidator(new String[] {"0", "1", "2"}));
+        VALIDATORS.put(Secure.ACCESSIBILITY_CAPTIONING_EDGE_COLOR, ANY_INTEGER_VALIDATOR);
+        VALIDATORS.put(
+                Secure.ACCESSIBILITY_CAPTIONING_TYPEFACE,
+                new DiscreteValueValidator(
+                        new String[] {"DEFAULT", "MONOSPACE", "SANS_SERIF", "SERIF"}));
+        VALIDATORS.put(
+                Secure.ACCESSIBILITY_CAPTIONING_FONT_SCALE,
+                new InclusiveFloatRangeValidator(0.5f, 2.0f));
+        VALIDATORS.put(Secure.ACCESSIBILITY_CAPTIONING_WINDOW_COLOR, ANY_INTEGER_VALIDATOR);
+        VALIDATORS.put(Secure.TTS_DEFAULT_RATE, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(Secure.TTS_DEFAULT_PITCH, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(Secure.TTS_DEFAULT_SYNTH, PACKAGE_NAME_VALIDATOR);
+        VALIDATORS.put(Secure.TTS_ENABLED_PLUGINS, new PackageNameListValidator(" "));
+        VALIDATORS.put(Secure.TTS_DEFAULT_LOCALE, TTS_LIST_VALIDATOR);
+        VALIDATORS.put(Secure.SHOW_IME_WITH_HARD_KEYBOARD, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(Secure.WIFI_NUM_OPEN_NETWORKS_KEPT, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(Secure.MOUNT_PLAY_NOTIFICATION_SND, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.MOUNT_UMS_AUTOSTART, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.MOUNT_UMS_PROMPT, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.MOUNT_UMS_NOTIFY_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.DOUBLE_TAP_TO_WAKE, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.WAKE_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.LONG_PRESS_TIMEOUT, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(Secure.CAMERA_GESTURE_DISABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.ACCESSIBILITY_AUTOCLICK_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.ACCESSIBILITY_AUTOCLICK_DELAY, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(Secure.ACCESSIBILITY_LARGE_POINTER_ICON, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(
+                Secure.PREFERRED_TTY_MODE,
+                new DiscreteValueValidator(new String[] {"0", "1", "2", "3"}));
+        VALIDATORS.put(Secure.ENHANCED_VOICE_PRIVACY_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.TTY_MODE_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.RTT_CALLING_MODE, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(
+                Secure.INCALL_POWER_BUTTON_BEHAVIOR,
+                new DiscreteValueValidator(new String[] {"1", "2"}));
+        VALIDATORS.put(Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(Secure.NIGHT_DISPLAY_AUTO_MODE, new InclusiveIntegerRangeValidator(0, 2));
+        VALIDATORS.put(Secure.DISPLAY_WHITE_BALANCE_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.SYNC_PARENT_SOUNDS, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.SYSTEM_NAVIGATION_KEYS_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.QS_TILES, TILE_LIST_VALIDATOR);
+        VALIDATORS.put(Secure.DOZE_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.DOZE_ALWAYS_ON, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.DOZE_PICK_UP_GESTURE, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.DOZE_DOUBLE_TAP_GESTURE, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.DOZE_TAP_SCREEN_GESTURE, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.DOZE_WAKE_DISPLAY_GESTURE, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.NFC_PAYMENT_DEFAULT_COMPONENT, COMPONENT_NAME_VALIDATOR);
+        VALIDATORS.put(
+                Secure.AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(Secure.FACE_UNLOCK_KEYGUARD_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.FACE_UNLOCK_DISMISSES_KEYGUARD, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.SHOW_MEDIA_WHEN_BYPASSING, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.FACE_UNLOCK_APP_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.ASSIST_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.ASSIST_GESTURE_SILENCE_ALERTS_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.ASSIST_GESTURE_WAKE_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.VR_DISPLAY_MODE, new DiscreteValueValidator(new String[] {"0", "1"}));
+        VALIDATORS.put(Secure.NOTIFICATION_BADGING, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.NOTIFICATION_BUBBLES, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.NOTIFICATION_DISMISS_RTL, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.QS_AUTO_ADDED_TILES, TILE_LIST_VALIDATOR);
+        VALIDATORS.put(Secure.SCREENSAVER_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.SCREENSAVER_COMPONENTS, COMMA_SEPARATED_COMPONENT_LIST_VALIDATOR);
+        VALIDATORS.put(Secure.SCREENSAVER_ACTIVATE_ON_DOCK, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.LOCKDOWN_IN_POWER_MENU, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.VOLUME_HUSH_GESTURE, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(
+                Secure.ENABLED_NOTIFICATION_LISTENERS,
+                COLON_SEPARATED_COMPONENT_LIST_VALIDATOR); // legacy restore setting
+        VALIDATORS.put(
+                Secure.ENABLED_NOTIFICATION_ASSISTANT,
+                COLON_SEPARATED_COMPONENT_LIST_VALIDATOR); // legacy restore setting
+        VALIDATORS.put(
+                Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
+                COLON_SEPARATED_PACKAGE_LIST_VALIDATOR); // legacy restore setting
+        VALIDATORS.put(Secure.HUSH_GESTURE_USED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.MANUAL_RINGER_TOGGLE_COUNT, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(Secure.IN_CALL_NOTIFICATION_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, BOOLEAN_VALIDATOR);
+        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.ZEN_DURATION, ANY_INTEGER_VALIDATOR);
+        VALIDATORS.put(Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.SHOW_ZEN_SETTINGS_SUGGESTION, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.ZEN_SETTINGS_UPDATED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.ZEN_SETTINGS_SUGGESTION_VIEWED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.CHARGING_SOUNDS_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.CHARGING_VIBRATION_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(
+                Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(
+                Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(Secure.USER_SETUP_COMPLETE, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.ASSIST_GESTURE_SETUP_COMPLETE, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.TRUST_AGENTS_EXTEND_UNLOCK, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE, JSON_OBJECT_VALIDATOR);
+        VALIDATORS.put(Secure.LOCK_SCREEN_WHEN_TRUST_LOST, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.SKIP_GESTURE, BOOLEAN_VALIDATOR);
+        /*
+         * Only used if FeatureFlag "settings_skip_direction_mutable" is enabled.
+         * If feature flag is disabled, should assume SKIP_DIRECTION = 0.
+         *      0 / false = right to left to advance to next
+         *      1 / true = left to right to advance to next
+         */
+        VALIDATORS.put(Secure.SKIP_DIRECTION, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.SILENCE_GESTURE, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES, JSON_OBJECT_VALIDATOR);
+        VALIDATORS.put(
+                Secure.NAVIGATION_MODE, new DiscreteValueValidator(new String[] {"0", "1", "2"}));
+        VALIDATORS.put(Secure.AWARE_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.SKIP_GESTURE_COUNT, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(Secure.SKIP_TOUCH_COUNT, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(Secure.SILENCE_ALARMS_GESTURE_COUNT, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(Secure.SILENCE_TIMER_GESTURE_COUNT, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(Secure.SILENCE_CALL_GESTURE_COUNT, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(Secure.SILENCE_ALARMS_TOUCH_COUNT, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(Secure.SILENCE_TIMER_TOUCH_COUNT, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(Secure.SILENCE_CALL_TOUCH_COUNT, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(Secure.ODI_CAPTIONS_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.DARK_MODE_DIALOG_SEEN, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.UI_NIGHT_MODE, new InclusiveIntegerRangeValidator(0, 2));
+        VALIDATORS.put(Secure.GLOBAL_ACTIONS_PANEL_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.AWARE_LOCK_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.DISPLAY_DENSITY_FORCED, NON_NEGATIVE_INTEGER_VALIDATOR);
+    }
+}
diff --git a/core/java/android/provider/settings/validators/SettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
similarity index 87%
rename from core/java/android/provider/settings/validators/SettingsValidators.java
rename to packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
index 562c638..224042c 100644
--- a/core/java/android/provider/settings/validators/SettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
@@ -24,6 +24,7 @@
 import org.json.JSONException;
 import org.json.JSONObject;
 
+import java.text.SimpleDateFormat;
 import java.util.Locale;
 
 /**
@@ -180,4 +181,27 @@
     public static final Validator TTS_LIST_VALIDATOR = new TTSListValidator();
 
     public static final Validator TILE_LIST_VALIDATOR = new TileListValidator();
+
+    static final Validator DATE_FORMAT_VALIDATOR = value -> {
+        try {
+            new SimpleDateFormat(value);
+            return true;
+        } catch (IllegalArgumentException | NullPointerException e) {
+            return false;
+        }
+    };
+
+    static final Validator COLON_SEPARATED_COMPONENT_LIST_VALIDATOR =
+            new ComponentNameListValidator(":");
+
+    static final Validator COLON_SEPARATED_PACKAGE_LIST_VALIDATOR =
+            new PackageNameListValidator(":");
+
+    static final Validator COMMA_SEPARATED_COMPONENT_LIST_VALIDATOR =
+            new ComponentNameListValidator(",");
+
+    static final Validator PERCENTAGE_INTEGER_VALIDATOR =
+            new InclusiveIntegerRangeValidator(0, 100);
+
+    static final Validator VIBRATION_INTENSITY_VALIDATOR = new InclusiveIntegerRangeValidator(0, 3);
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
new file mode 100644
index 0000000..94ab0f1
--- /dev/null
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -0,0 +1,220 @@
+/*
+ * 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.BOOLEAN_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.COMPONENT_NAME_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.DATE_FORMAT_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.LENIENT_IP_ADDRESS_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.NON_NEGATIVE_INTEGER_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.URI_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.VIBRATION_INTENSITY_VALIDATOR;
+
+import android.annotation.Nullable;
+import android.annotation.UnsupportedAppUsage;
+import android.content.ComponentName;
+import android.hardware.display.ColorDisplayManager;
+import android.os.BatteryManager;
+import android.provider.Settings.System;
+import android.util.ArrayMap;
+
+import java.util.Map;
+
+/**
+ * Validators for System settings
+ */
+public class SystemSettingsValidators {
+    /**
+     * These are all public system settings
+     *
+     * <p>All settings in {@link System.SETTINGS_TO_BACKUP} array *must* have a non-null validator,
+     * otherwise they won't be restored.
+     */
+    @UnsupportedAppUsage
+    public static final Map<String, Validator> VALIDATORS = new ArrayMap<>();
+
+    static {
+        VALIDATORS.put(
+                System.STAY_ON_WHILE_PLUGGED_IN,
+                value -> {
+                    try {
+                        int val = Integer.parseInt(value);
+                        return (val == 0)
+                                || (val == BatteryManager.BATTERY_PLUGGED_AC)
+                                || (val == BatteryManager.BATTERY_PLUGGED_USB)
+                                || (val == BatteryManager.BATTERY_PLUGGED_WIRELESS)
+                                || (val
+                                        == (BatteryManager.BATTERY_PLUGGED_AC
+                                                | BatteryManager.BATTERY_PLUGGED_USB))
+                                || (val
+                                        == (BatteryManager.BATTERY_PLUGGED_AC
+                                                | BatteryManager.BATTERY_PLUGGED_WIRELESS))
+                                || (val
+                                        == (BatteryManager.BATTERY_PLUGGED_USB
+                                                | BatteryManager.BATTERY_PLUGGED_WIRELESS))
+                                || (val
+                                        == (BatteryManager.BATTERY_PLUGGED_AC
+                                                | BatteryManager.BATTERY_PLUGGED_USB
+                                                | BatteryManager.BATTERY_PLUGGED_WIRELESS));
+                    } catch (NumberFormatException e) {
+                        return false;
+                    }
+                });
+        VALIDATORS.put(System.END_BUTTON_BEHAVIOR, new InclusiveIntegerRangeValidator(0, 3));
+        VALIDATORS.put(System.WIFI_USE_STATIC_IP, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.BLUETOOTH_DISCOVERABILITY, new InclusiveIntegerRangeValidator(0, 2));
+        VALIDATORS.put(System.BLUETOOTH_DISCOVERABILITY_TIMEOUT, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(
+                System.NEXT_ALARM_FORMATTED,
+                new Validator() {
+                    private static final int MAX_LENGTH = 1000;
+
+                    @Override
+                    public boolean validate(String value) {
+                        // TODO: No idea what the correct format is.
+                        return value == null || value.length() < MAX_LENGTH;
+                    }
+                });
+        VALIDATORS.put(
+                System.FONT_SCALE,
+                value -> {
+                    try {
+                        return Float.parseFloat(value) >= 0;
+                    } catch (NumberFormatException | NullPointerException e) {
+                        return false;
+                    }
+                });
+        VALIDATORS.put(System.DIM_SCREEN, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(
+                System.DISPLAY_COLOR_MODE,
+                new Validator() {
+                    @Override
+                    public boolean validate(@Nullable String value) {
+                        // Assume the actual validation that this device can properly handle this
+                        // kind of
+                        // color mode further down in ColorDisplayManager / ColorDisplayService.
+                        try {
+                            final int setting = Integer.parseInt(value);
+                            final boolean isInFrameworkRange =
+                                    setting >= ColorDisplayManager.COLOR_MODE_NATURAL
+                                            && setting <= ColorDisplayManager.COLOR_MODE_AUTOMATIC;
+                            final boolean isInVendorRange =
+                                    setting >= ColorDisplayManager.VENDOR_COLOR_MODE_RANGE_MIN
+                                            && setting
+                                                    <= ColorDisplayManager
+                                                            .VENDOR_COLOR_MODE_RANGE_MAX;
+                            return isInFrameworkRange || isInVendorRange;
+                        } catch (NumberFormatException | NullPointerException e) {
+                            return false;
+                        }
+                    }
+                });
+        VALIDATORS.put(System.SCREEN_OFF_TIMEOUT, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(System.SCREEN_BRIGHTNESS_FOR_VR, new InclusiveIntegerRangeValidator(0, 255));
+        VALIDATORS.put(System.SCREEN_BRIGHTNESS_MODE, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.ADAPTIVE_SLEEP, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.MODE_RINGER_STREAMS_AFFECTED, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(System.MUTE_STREAMS_AFFECTED, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(System.VIBRATE_ON, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);
+        VALIDATORS.put(System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);
+        VALIDATORS.put(System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);
+        VALIDATORS.put(System.RINGTONE, URI_VALIDATOR);
+        VALIDATORS.put(System.NOTIFICATION_SOUND, URI_VALIDATOR);
+        VALIDATORS.put(System.ALARM_ALERT, URI_VALIDATOR);
+        VALIDATORS.put(System.TEXT_AUTO_REPLACE, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.TEXT_AUTO_CAPS, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.TEXT_AUTO_PUNCTUATE, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.TEXT_SHOW_PASSWORD, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.AUTO_TIME, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.AUTO_TIME_ZONE, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.SHOW_GTALK_SERVICE_STATUS, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(
+                System.WALLPAPER_ACTIVITY,
+                new Validator() {
+                    private static final int MAX_LENGTH = 1000;
+
+                    @Override
+                    public boolean validate(String value) {
+                        if (value != null && value.length() > MAX_LENGTH) {
+                            return false;
+                        }
+                        return ComponentName.unflattenFromString(value) != null;
+                    }
+                });
+        VALIDATORS.put(
+                System.TIME_12_24, new DiscreteValueValidator(new String[] {"12", "24", null}));
+        VALIDATORS.put(System.DATE_FORMAT, DATE_FORMAT_VALIDATOR);
+        VALIDATORS.put(System.SETUP_WIZARD_HAS_RUN, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.ACCELEROMETER_ROTATION, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.USER_ROTATION, new InclusiveIntegerRangeValidator(0, 3));
+        VALIDATORS.put(System.DTMF_TONE_WHEN_DIALING, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.SOUND_EFFECTS_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.HAPTIC_FEEDBACK_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.POWER_SOUNDS_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.DOCK_SOUNDS_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.SHOW_WEB_SUGGESTIONS, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.WIFI_USE_STATIC_IP, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.ADVANCED_SETTINGS, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.SCREEN_AUTO_BRIGHTNESS_ADJ, new InclusiveFloatRangeValidator(-1, 1));
+        VALIDATORS.put(System.VIBRATE_INPUT_DEVICES, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.MASTER_MONO, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.MASTER_BALANCE, new InclusiveFloatRangeValidator(-1.f, 1.f));
+        VALIDATORS.put(System.NOTIFICATIONS_USE_RING_VOLUME, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.VIBRATE_IN_SILENT, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.MEDIA_BUTTON_RECEIVER, COMPONENT_NAME_VALIDATOR);
+        VALIDATORS.put(System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.VIBRATE_WHEN_RINGING, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.DTMF_TONE_TYPE_WHEN_DIALING, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.HEARING_AID, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.TTY_MODE, new InclusiveIntegerRangeValidator(0, 3));
+        VALIDATORS.put(System.NOTIFICATION_LIGHT_PULSE, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.POINTER_LOCATION, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.SHOW_TOUCHES, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.WINDOW_ORIENTATION_LISTENER_LOG, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.LOCKSCREEN_SOUNDS_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.LOCKSCREEN_DISABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.SIP_RECEIVE_CALLS, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(
+                System.SIP_CALL_OPTIONS,
+                new DiscreteValueValidator(new String[] {"SIP_ALWAYS", "SIP_ADDRESS_ONLY"}));
+        VALIDATORS.put(System.SIP_ALWAYS, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.SIP_ADDRESS_ONLY, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.SIP_ASK_ME_EACH_TIME, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.POINTER_SPEED, new InclusiveFloatRangeValidator(-7, 7));
+        VALIDATORS.put(System.LOCK_TO_APP_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(
+                System.EGG_MODE,
+                new Validator() {
+                    @Override
+                    public boolean validate(@Nullable String value) {
+                        try {
+                            return Long.parseLong(value) >= 0;
+                        } catch (NumberFormatException e) {
+                            return false;
+                        }
+                    }
+                });
+        VALIDATORS.put(System.WIFI_STATIC_IP, LENIENT_IP_ADDRESS_VALIDATOR);
+        VALIDATORS.put(System.WIFI_STATIC_GATEWAY, LENIENT_IP_ADDRESS_VALIDATOR);
+        VALIDATORS.put(System.WIFI_STATIC_NETMASK, LENIENT_IP_ADDRESS_VALIDATOR);
+        VALIDATORS.put(System.WIFI_STATIC_DNS1, LENIENT_IP_ADDRESS_VALIDATOR);
+        VALIDATORS.put(System.WIFI_STATIC_DNS2, LENIENT_IP_ADDRESS_VALIDATOR);
+        VALIDATORS.put(System.SHOW_BATTERY_PERCENT, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.NOTIFICATION_LIGHT_PULSE, BOOLEAN_VALIDATOR);
+    }
+}
diff --git a/core/java/android/provider/settings/validators/TTSListValidator.java b/packages/SettingsProvider/src/android/provider/settings/validators/TTSListValidator.java
similarity index 100%
rename from core/java/android/provider/settings/validators/TTSListValidator.java
rename to packages/SettingsProvider/src/android/provider/settings/validators/TTSListValidator.java
diff --git a/core/java/android/provider/settings/validators/TileListValidator.java b/packages/SettingsProvider/src/android/provider/settings/validators/TileListValidator.java
similarity index 100%
rename from core/java/android/provider/settings/validators/TileListValidator.java
rename to packages/SettingsProvider/src/android/provider/settings/validators/TileListValidator.java
diff --git a/core/java/android/provider/settings/validators/Validator.java b/packages/SettingsProvider/src/android/provider/settings/validators/Validator.java
similarity index 100%
rename from core/java/android/provider/settings/validators/Validator.java
rename to packages/SettingsProvider/src/android/provider/settings/validators/Validator.java
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 36e945f..f545fa6 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -34,6 +34,12 @@
 import android.os.ParcelFileDescriptor;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.provider.settings.backup.GlobalSettings;
+import android.provider.settings.backup.SecureSettings;
+import android.provider.settings.backup.SystemSettings;
+import android.provider.settings.validators.GlobalSettingsValidators;
+import android.provider.settings.validators.SecureSettingsValidators;
+import android.provider.settings.validators.SystemSettingsValidators;
 import android.provider.settings.validators.Validator;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -45,7 +51,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.widget.LockPatternUtils;
-import com.android.settingslib.display.DisplayDensityUtils;
+import com.android.settingslib.display.DisplayDensityConfiguration;
 
 import java.io.BufferedOutputStream;
 import java.io.ByteArrayInputStream;
@@ -542,7 +548,7 @@
         Cursor cursor = getContentResolver().query(Settings.System.CONTENT_URI, PROJECTION, null,
                 null, null);
         try {
-            return extractRelevantValues(cursor, Settings.System.SETTINGS_TO_BACKUP);
+            return extractRelevantValues(cursor, SystemSettings.SETTINGS_TO_BACKUP);
         } finally {
             cursor.close();
         }
@@ -552,7 +558,7 @@
         Cursor cursor = getContentResolver().query(Settings.Secure.CONTENT_URI, PROJECTION, null,
                 null, null);
         try {
-            return extractRelevantValues(cursor, Settings.Secure.SETTINGS_TO_BACKUP);
+            return extractRelevantValues(cursor, SecureSettings.SETTINGS_TO_BACKUP);
         } finally {
             cursor.close();
         }
@@ -562,7 +568,7 @@
         Cursor cursor = getContentResolver().query(Settings.Global.CONTENT_URI, PROJECTION, null,
                 null, null);
         try {
-            return extractRelevantValues(cursor, Settings.Global.SETTINGS_TO_BACKUP);
+            return extractRelevantValues(cursor, GlobalSettings.SETTINGS_TO_BACKUP);
         } finally {
             cursor.close();
         }
@@ -633,18 +639,18 @@
         final String[] whitelist;
         Map<String, Validator> validators = null;
         if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
-            whitelist = ArrayUtils.concatElements(String.class, Settings.Secure.SETTINGS_TO_BACKUP,
+            whitelist = ArrayUtils.concatElements(String.class, SecureSettings.SETTINGS_TO_BACKUP,
                     Settings.Secure.LEGACY_RESTORE_SETTINGS,
                     Settings.Secure.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP);
-            validators = Settings.Secure.VALIDATORS;
+            validators = SecureSettingsValidators.VALIDATORS;
         } else if (contentUri.equals(Settings.System.CONTENT_URI)) {
-            whitelist = ArrayUtils.concatElements(String.class, Settings.System.SETTINGS_TO_BACKUP,
+            whitelist = ArrayUtils.concatElements(String.class, SystemSettings.SETTINGS_TO_BACKUP,
                     Settings.System.LEGACY_RESTORE_SETTINGS);
-            validators = Settings.System.VALIDATORS;
+            validators = SystemSettingsValidators.VALIDATORS;
         } else if (contentUri.equals(Settings.Global.CONTENT_URI)) {
-            whitelist = ArrayUtils.concatElements(String.class, Settings.Global.SETTINGS_TO_BACKUP,
+            whitelist = ArrayUtils.concatElements(String.class, GlobalSettings.SETTINGS_TO_BACKUP,
                     Settings.Global.LEGACY_RESTORE_SETTINGS);
-            validators = Settings.Global.VALIDATORS;
+            validators = GlobalSettingsValidators.VALIDATORS;
         } else {
             throw new IllegalArgumentException("Unknown URI: " + contentUri);
         }
@@ -1035,7 +1041,8 @@
 
         if (previousDensity == null || previousDensity != newDensity) {
             // From nothing to something is a change.
-            DisplayDensityUtils.setForcedDisplayDensity(Display.DEFAULT_DISPLAY, newDensity);
+            DisplayDensityConfiguration.setForcedDisplayDensity(
+                    Display.DEFAULT_DISPLAY, newDensity);
         }
     }
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index e492e28..4d71e72b5 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -70,6 +70,7 @@
 import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
+import android.provider.settings.validators.SystemSettingsValidators;
 import android.provider.settings.validators.Validator;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -1717,7 +1718,7 @@
     }
 
     private void validateSystemSettingValue(String name, String value) {
-        Validator validator = Settings.System.VALIDATORS.get(name);
+        Validator validator = SystemSettingsValidators.VALIDATORS.get(name);
         if (validator != null && !validator.validate(value)) {
             throw new IllegalArgumentException("Invalid value: " + value
                     + " for setting: " + name);
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
similarity index 97%
rename from core/tests/coretests/src/android/provider/SettingsBackupTest.java
rename to packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index eef780a..d7eb7e95 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -18,15 +18,16 @@
 
 import static com.google.android.collect.Sets.newHashSet;
 
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.empty;
-import static org.hamcrest.Matchers.is;
+import static junit.framework.Assert.assertTrue;
 
 import static java.lang.reflect.Modifier.isFinal;
 import static java.lang.reflect.Modifier.isPublic;
 import static java.lang.reflect.Modifier.isStatic;
 
 import android.platform.test.annotations.Presubmit;
+import android.provider.settings.backup.GlobalSettings;
+import android.provider.settings.backup.SecureSettings;
+import android.provider.settings.backup.SystemSettings;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -727,45 +728,43 @@
     public void systemSettingsBackedUpOrBlacklisted() {
         checkSettingsBackedUpOrBlacklisted(
                 getCandidateSettings(Settings.System.class),
-                newHashSet(Settings.System.SETTINGS_TO_BACKUP),
+                newHashSet(SystemSettings.SETTINGS_TO_BACKUP),
                 BACKUP_BLACKLISTED_SYSTEM_SETTINGS);
     }
 
     @Test
     public void globalSettingsBackedUpOrBlacklisted() {
         checkSettingsBackedUpOrBlacklisted(
-            getCandidateSettings(Settings.Global.class),
-            newHashSet(Settings.Global.SETTINGS_TO_BACKUP),
-            BACKUP_BLACKLISTED_GLOBAL_SETTINGS);
+                getCandidateSettings(Settings.Global.class),
+                newHashSet(GlobalSettings.SETTINGS_TO_BACKUP),
+                BACKUP_BLACKLISTED_GLOBAL_SETTINGS);
     }
 
     @Test
     public void secureSettingsBackedUpOrBlacklisted() {
         HashSet<String> keys = new HashSet<String>();
-        Collections.addAll(keys, Settings.Secure.SETTINGS_TO_BACKUP);
+        Collections.addAll(keys, SecureSettings.SETTINGS_TO_BACKUP);
         Collections.addAll(keys, Settings.Secure.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP);
         checkSettingsBackedUpOrBlacklisted(
                 getCandidateSettings(Settings.Secure.class),
                 keys,
-            BACKUP_BLACKLISTED_SECURE_SETTINGS);
+                BACKUP_BLACKLISTED_SECURE_SETTINGS);
     }
 
     private static void checkSettingsBackedUpOrBlacklisted(
             Set<String> settings, Set<String> settingsToBackup, Set<String> blacklist) {
         Set<String> settingsNotBackedUp = difference(settings, settingsToBackup);
         Set<String> settingsNotBackedUpOrBlacklisted = difference(settingsNotBackedUp, blacklist);
-        assertThat(
+        assertTrue(
                 "Settings not backed up or blacklisted",
-                settingsNotBackedUpOrBlacklisted,
-                is(empty()));
+                settingsNotBackedUpOrBlacklisted.isEmpty());
 
-        assertThat(
-                "blacklisted settings backed up",
-                intersect(settingsToBackup, blacklist),
-                is(empty()));
+        assertTrue(
+                "blacklisted settings backed up", intersect(settingsToBackup, blacklist).isEmpty());
     }
 
-    private static Set<String> getCandidateSettings(Class<? extends Settings.NameValueTable> clazz) {
+    private static Set<String> getCandidateSettings(
+            Class<? extends Settings.NameValueTable> clazz) {
         HashSet<String> result = new HashSet<String>();
         for (Field field : clazz.getDeclaredFields()) {
             if (looksLikeValidSetting(field)) {
diff --git a/core/tests/coretests/src/android/provider/settings/validators/SettingsValidatorsTest.java b/packages/SettingsProvider/test/src/android/provider/settings/validators/SettingsValidatorsTest.java
similarity index 92%
rename from core/tests/coretests/src/android/provider/settings/validators/SettingsValidatorsTest.java
rename to packages/SettingsProvider/test/src/android/provider/settings/validators/SettingsValidatorsTest.java
index 5f042d3..a3b0835 100644
--- a/core/tests/coretests/src/android/provider/settings/validators/SettingsValidatorsTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/settings/validators/SettingsValidatorsTest.java
@@ -24,6 +24,9 @@
 
 import android.platform.test.annotations.Presubmit;
 import android.provider.Settings;
+import android.provider.settings.backup.GlobalSettings;
+import android.provider.settings.backup.SecureSettings;
+import android.provider.settings.backup.SystemSettings;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -218,7 +221,7 @@
 
     @Test
     public void dateFormatValidator_onNullValue_returnsFalse() {
-        assertFalse(Settings.System.DATE_FORMAT_VALIDATOR.validate(null));
+        assertFalse(SettingsValidators.DATE_FORMAT_VALIDATOR.validate(null));
     }
 
     @Test
@@ -238,18 +241,18 @@
 
     @Test
     public void testJSONObjectValidator_onNullValue_returnsFalse() {
-        assertThat(SettingsValidators.JSON_OBJECT_VALIDATOR.validate(null)).isFalse();
+        assertFalse(SettingsValidators.JSON_OBJECT_VALIDATOR.validate(null));
     }
 
     @Test
     public void testJSONObjectValidator_onEmptyString_returnsFalse() {
-        assertThat(SettingsValidators.JSON_OBJECT_VALIDATOR.validate("")).isFalse();
+        assertFalse(SettingsValidators.JSON_OBJECT_VALIDATOR.validate(""));
     }
 
     @Test
     public void ensureAllBackedUpSystemSettingsHaveValidators() {
-        String offenders = getOffenders(concat(Settings.System.SETTINGS_TO_BACKUP,
-                Settings.System.LEGACY_RESTORE_SETTINGS), Settings.System.VALIDATORS);
+        String offenders = getOffenders(concat(SystemSettings.SETTINGS_TO_BACKUP,
+                Settings.System.LEGACY_RESTORE_SETTINGS), SystemSettingsValidators.VALIDATORS);
 
         failIfOffendersPresent(offenders, "Settings.System");
     }
@@ -295,16 +298,16 @@
 
     @Test
     public void ensureAllBackedUpGlobalSettingsHaveValidators() {
-        String offenders = getOffenders(concat(Settings.Global.SETTINGS_TO_BACKUP,
-                Settings.Global.LEGACY_RESTORE_SETTINGS), Settings.Global.VALIDATORS);
+        String offenders = getOffenders(concat(GlobalSettings.SETTINGS_TO_BACKUP,
+                Settings.Global.LEGACY_RESTORE_SETTINGS), GlobalSettingsValidators.VALIDATORS);
 
         failIfOffendersPresent(offenders, "Settings.Global");
     }
 
     @Test
     public void ensureAllBackedUpSecureSettingsHaveValidators() {
-        String offenders = getOffenders(concat(Settings.Secure.SETTINGS_TO_BACKUP,
-                Settings.Secure.LEGACY_RESTORE_SETTINGS), Settings.Secure.VALIDATORS);
+        String offenders = getOffenders(concat(SecureSettings.SETTINGS_TO_BACKUP,
+                Settings.Secure.LEGACY_RESTORE_SETTINGS), SecureSettingsValidators.VALIDATORS);
 
         failIfOffendersPresent(offenders, "Settings.Secure");
     }
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java
index 68efa67..ce1da4a 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java
@@ -31,6 +31,8 @@
 
 import libcore.io.Streams;
 
+import org.junit.After;
+import org.junit.Before;
 import org.junit.runner.RunWith;
 
 import java.io.FileInputStream;
@@ -60,6 +62,20 @@
 
     private int mSecondaryUserId = Integer.MIN_VALUE;
 
+    @Before
+    public void setUp() {
+        Settings.Global.clearProviderForTest();
+        Settings.Secure.clearProviderForTest();
+        Settings.System.clearProviderForTest();
+    }
+
+    @After
+    public void tearDown() {
+        Settings.Global.clearProviderForTest();
+        Settings.Secure.clearProviderForTest();
+        Settings.System.clearProviderForTest();
+    }
+
     protected void setStringViaFrontEndApiSetting(int type, String name, String value, int userId) {
         ContentResolver contentResolver = getContext().getContentResolver();
 
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/InstallNonMarketAppsDeprecationTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/InstallNonMarketAppsDeprecationTest.java
index 863b035..ff11f70 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/InstallNonMarketAppsDeprecationTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/InstallNonMarketAppsDeprecationTest.java
@@ -84,8 +84,10 @@
         return line.trim();
     }
 
+    @Override
     @Before
     public void setUp() {
+        super.setUp();
         mUm = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
         mHasUserRestriction = mUm.hasUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
         mSystemSetUserRestriction = mUm.getUserRestrictionSource(
@@ -145,8 +147,10 @@
         assertTrue("Invalid value", value.equals("1") || value.equals("0"));
     }
 
+    @Override
     @After
     public void tearDown() {
+        super.tearDown();
         if (!mHasUserRestriction || mSystemSetUserRestriction) {
             // The test may have modified the user restriction state. Restore it.
             mUm.setUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java
index cf8e1a5..12ca92f 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java
@@ -64,8 +64,10 @@
     private TestFriendlySettingsBackupAgent mAgentUnderTest;
     private Context mContext;
 
+    @Override
     @Before
     public void setUp() {
+        super.setUp();
         mContext = new ContextWithMockContentResolver(getContext());
 
         mAgentUnderTest = new TestFriendlySettingsBackupAgent();
diff --git a/packages/SystemUI/res/drawable/ic_5g_e_mobiledata.xml b/packages/SystemUI/res/drawable/ic_5g_e_mobiledata.xml
index fe1bb26..7c7c8c1 100644
--- a/packages/SystemUI/res/drawable/ic_5g_e_mobiledata.xml
+++ b/packages/SystemUI/res/drawable/ic_5g_e_mobiledata.xml
@@ -16,16 +16,10 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:viewportWidth="22"
     android:viewportHeight="17"
-    android:width="22dp"
-    android:height="17dp">
+    android:width="19.41dp"
+    android:height="15dp">
   <path
       android:fillColor="#FFFFFFFF"
-      android:pathData="M1.22,8.49l0.43-4.96h4.33v1.17H2.67L2.44,7.41c0.41-0.29,0.85-0.43,1.33-0.43c0.77,0,1.38,0.3,1.83,0.9 s0.66,1.41,0.66,2.43c0,1.03-0.24,1.84-0.72,2.43s-1.14,0.88-1.98,0.88c-0.75,0-1.36-0.24-1.83-0.73s-0.74-1.16-0.81-2.02h1.13 c0.07,0.57,0.23,1,0.49,1.29c0.26,0.29,0.59,0.43,1.01,0.43c0.47,0,0.84-0.2,1.1-0.61c0.26-0.41,0.4-0.96,0.4-1.65 c0-0.65-0.14-1.18-0.43-1.59S3.96,8.11,3.47,8.11c-0.4,0-0.72,0.1-0.96,0.31L2.19,8.75L1.22,8.49z" />
-  <path
-      android:fillColor="#FFFFFFFF"
-      android:pathData="M14.14,12.24l-0.22,0.27c-0.63,0.73-1.55,1.1-2.76,1.1c-1.08,0-1.92-0.36-2.53-1.07c-0.61-0.71-0.93-1.72-0.94-3.02V7.56 c0-1.39,0.28-2.44,0.84-3.13c0.56-0.7,1.39-1.04,2.51-1.04c0.95,0,1.69,0.26,2.23,0.79c0.54,0.53,0.83,1.28,0.89,2.26h-1.25 c-0.05-0.62-0.22-1.1-0.52-1.45c-0.29-0.35-0.74-0.52-1.34-0.52c-0.72,0-1.24,0.23-1.57,0.7C9.14,5.63,8.96,6.37,8.95,7.4v2.03 c0,1,0.19,1.77,0.57,2.31c0.38,0.54,0.93,0.8,1.65,0.8c0.67,0,1.19-0.16,1.54-0.49l0.18-0.17V9.59h-1.82V8.52h3.07V12.24z" />
-  <path
-      android:fillColor="#FFFFFFFF"
-      android:pathData="M20.96,8.88h-3.52v3.53h4.1v1.07h-5.35V3.52h5.28V4.6h-4.03V7.8h3.52V8.88z" />
-
+      android:pathData="M 6.72 3.52 L 6.54 4.69 L 3.34 4.69 L 2.63 7.41 C 3.011 7.143 3.465 7 3.93 7 C 4.5 6.986 5.041 7.251 5.38 7.71 C 5.756 8.249 5.952 8.893 5.94 9.55 C 5.98 10.276 5.864 11.002 5.6 11.68 C 5.385 12.267 5.007 12.78 4.51 13.16 C 4.043 13.499 3.476 13.671 2.9 13.65 C 2.271 13.653 1.675 13.369 1.28 12.88 C 0.854 12.302 0.636 11.597 0.66 10.88 L 1.76 10.88 C 1.81 12 2.21 12.57 3 12.58 C 3.592 12.589 4.132 12.243 4.37 11.7 C 4.708 11.044 4.85 10.305 4.78 9.57 C 4.767 9.209 4.645 8.86 4.43 8.57 C 4.239 8.309 3.934 8.156 3.61 8.16 C 3.404 8.138 3.196 8.162 3 8.23 C 2.748 8.358 2.518 8.527 2.32 8.73 L 1.31 8.46 L 2.51 3.52 L 6.72 3.52 Z M 11.7 3.39 C 12.459 3.353 13.195 3.662 13.7 4.23 C 14.185 4.864 14.42 5.654 14.36 6.45 L 13.1 6.45 C 13.131 5.938 12.998 5.43 12.72 5 C 12.455 4.679 12.056 4.498 11.64 4.51 C 11.025 4.456 10.42 4.688 10 5.14 C 9.491 5.811 9.179 6.611 9.1 7.45 L 8.75 9.54 L 8.75 10.57 C 8.82 11.86 9.36 12.52 10.36 12.57 C 10.701 12.593 11.043 12.538 11.36 12.41 C 11.661 12.281 11.943 12.113 12.2 11.91 L 12.62 9.62 L 10.77 9.62 L 11 8.52 L 14 8.52 L 13.36 12.23 C 13.176 12.483 12.953 12.706 12.7 12.89 C 11.995 13.398 11.138 13.652 10.27 13.61 C 9.507 13.634 8.773 13.315 8.27 12.74 C 7.748 12.085 7.475 11.267 7.5 10.43 C 7.47 10.097 7.47 9.763 7.5 9.43 L 7.8 7.43 C 7.927 6.332 8.36 5.293 9.05 4.43 C 9.725 3.692 10.703 3.308 11.7 3.39 Z M 20.81 7.21 L 20.62 8.29 L 18.32 8.29 L 18.06 9.8 L 20.06 9.8 L 19.83 10.84 L 17.88 10.84 L 17.59 12.54 L 19.9 12.54 L 19.71 13.61 L 16.14 13.61 L 17.25 7.21 L 20.81 7.21 Z" />
+  <path android:pathData="M 0 0 H 14 V 17 H 0 V 0 Z"/>
 </vector>
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
index 45126f3..107d5cc 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
@@ -19,6 +19,8 @@
 import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
 import static android.telephony.PhoneStateListener.LISTEN_NONE;
 
+import static com.android.systemui.DejankUtils.whitelistIpcs;
+
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -33,6 +35,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import androidx.annotation.VisibleForTesting;
+
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.settingslib.WirelessUtils;
@@ -42,8 +46,6 @@
 import java.util.List;
 import java.util.Objects;
 
-import androidx.annotation.VisibleForTesting;
-
 /**
  * Controller that generates text including the carrier names and/or the status of all the SIM
  * interfaces in the device. Through a callback, the updates can be retrieved either as a list or
@@ -220,8 +222,9 @@
                 .getSystemService(Context.TELEPHONY_SERVICE));
         if (callback != null) {
             mCarrierTextCallback = callback;
-            if (ConnectivityManager.from(mContext).isNetworkSupported(
-                    ConnectivityManager.TYPE_MOBILE)) {
+            // TODO(b/140034799)
+            if (whitelistIpcs(() -> ConnectivityManager.from(mContext).isNetworkSupported(
+                    ConnectivityManager.TYPE_MOBILE))) {
                 mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
                 mKeyguardUpdateMonitor.registerCallback(mCallback);
                 mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
index 210b82d..979f3dc 100644
--- a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
@@ -16,6 +16,8 @@
 
 package com.android.keyguard;
 
+import static com.android.systemui.DejankUtils.whitelistIpcs;
+
 import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
 import android.content.Context;
@@ -132,7 +134,7 @@
                 return false;
             }
         });
-        updateEmergencyCallButton();
+        whitelistIpcs(this::updateEmergencyCallButton);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 169c97b..454f446 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -15,6 +15,8 @@
  */
 package com.android.keyguard;
 
+import static com.android.systemui.DejankUtils.whitelistIpcs;
+
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.admin.DevicePolicyManager;
@@ -467,8 +469,8 @@
      * @param turningOff true if the device is being turned off
      */
     void showPrimarySecurityScreen(boolean turningOff) {
-        SecurityMode securityMode = mSecurityModel.getSecurityMode(
-                KeyguardUpdateMonitor.getCurrentUser());
+        SecurityMode securityMode = whitelistIpcs(() -> mSecurityModel.getSecurityMode(
+                KeyguardUpdateMonitor.getCurrentUser()));
         if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")");
         showSecurityScreen(securityMode);
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
index 0cb6423..16e9ffc 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
@@ -15,6 +15,8 @@
  */
 package com.android.keyguard;
 
+import static com.android.systemui.DejankUtils.whitelistIpcs;
+
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.telephony.SubscriptionManager;
@@ -67,7 +69,9 @@
             return SecurityMode.SimPin;
         }
 
-        final int security = mLockPatternUtils.getActivePasswordQuality(userId);
+        // TODO(b/140034863)
+        final int security = whitelistIpcs(() ->
+                mLockPatternUtils.getActivePasswordQuality(userId));
         switch (security) {
             case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
             case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 6da2a42..aa1d8b4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -18,6 +18,8 @@
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.Intent.ACTION_USER_REMOVED;
+import static android.content.Intent.ACTION_USER_STOPPED;
 import static android.content.Intent.ACTION_USER_UNLOCKED;
 import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN;
 import static android.os.BatteryManager.BATTERY_STATUS_FULL;
@@ -36,6 +38,7 @@
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
+import static com.android.systemui.DejankUtils.whitelistIpcs;
 
 import android.annotation.AnyThread;
 import android.annotation.MainThread;
@@ -161,6 +164,8 @@
     private static final int MSG_DEVICE_POLICY_MANAGER_STATE_CHANGED = 337;
     private static final int MSG_TELEPHONY_CAPABLE = 338;
     private static final int MSG_TIMEZONE_UPDATE = 339;
+    private static final int MSG_USER_STOPPED = 340;
+    private static final int MSG_USER_REMOVED = 341;
 
     /** Biometric authentication state: Not listening. */
     private static final int BIOMETRIC_STATE_STOPPED = 0;
@@ -374,7 +379,13 @@
                     handleDreamingStateChanged(msg.arg1);
                     break;
                 case MSG_USER_UNLOCKED:
-                    handleUserUnlocked();
+                    handleUserUnlocked(msg.arg1);
+                    break;
+                case MSG_USER_STOPPED:
+                    handleUserStopped(msg.arg1);
+                    break;
+                case MSG_USER_REMOVED:
+                    handleUserRemoved(msg.arg1);
                     break;
                 case MSG_ASSISTANT_STACK_CHANGED:
                     setAssistantVisible((boolean) msg.obj);
@@ -426,6 +437,7 @@
                 }
             };
 
+    private SparseBooleanArray mUserIsUnlocked = new SparseBooleanArray();
     private SparseBooleanArray mUserHasTrust = new SparseBooleanArray();
     private SparseBooleanArray mUserTrustIsManaged = new SparseBooleanArray();
     private SparseBooleanArray mUserFingerprintAuthenticated = new SparseBooleanArray();
@@ -997,9 +1009,10 @@
     private boolean isFaceDisabled(int userId) {
         final DevicePolicyManager dpm =
                 (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
-        return dpm != null && (dpm.getKeyguardDisabledFeatures(null, userId)
+        // TODO(b/140035044)
+        return whitelistIpcs(() -> dpm != null && (dpm.getKeyguardDisabledFeatures(null, userId)
                 & DevicePolicyManager.KEYGUARD_DISABLE_FACE) != 0
-                || isSimPinSecure();
+                || isSimPinSecure());
     }
 
 
@@ -1205,7 +1218,14 @@
                     .equals(action)) {
                 mHandler.sendEmptyMessage(MSG_DPM_STATE_CHANGED);
             } else if (ACTION_USER_UNLOCKED.equals(action)) {
-                mHandler.sendEmptyMessage(MSG_USER_UNLOCKED);
+                mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_UNLOCKED,
+                        getSendingUserId(), 0));
+            } else if (ACTION_USER_STOPPED.equals(action)) {
+                mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_STOPPED,
+                        intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1), 0));
+            } else if (ACTION_USER_REMOVED.equals(action)) {
+                mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_REMOVED,
+                        intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1), 0));
             }
         }
     };
@@ -1556,8 +1576,9 @@
         }
     }
 
-    private void handleUserUnlocked() {
+    private void handleUserUnlocked(int userId) {
         checkIsHandlerThread();
+        mUserIsUnlocked.put(userId, true);
         mNeedsSlowUnlockTransition = resolveNeedsSlowUnlockTransition();
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
@@ -1567,6 +1588,16 @@
         }
     }
 
+    private void handleUserStopped(int userId) {
+        checkIsHandlerThread();
+        mUserIsUnlocked.put(userId, mUserManager.isUserUnlocked(userId));
+    }
+
+    private void handleUserRemoved(int userId) {
+        checkIsHandlerThread();
+        mUserIsUnlocked.delete(userId);
+    }
+
     @VisibleForTesting
     protected KeyguardUpdateMonitor(Context context) {
         mContext = context;
@@ -1610,6 +1641,8 @@
         allUserFilter.addAction(ACTION_FACE_UNLOCK_STOPPED);
         allUserFilter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
         allUserFilter.addAction(ACTION_USER_UNLOCKED);
+        allUserFilter.addAction(ACTION_USER_STOPPED);
+        allUserFilter.addAction(ACTION_USER_REMOVED);
         context.registerReceiverAsUser(mBroadcastAllReceiver, UserHandle.ALL, allUserFilter,
                 null, mHandler);
 
@@ -1664,6 +1697,8 @@
         ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
         mUserManager = context.getSystemService(UserManager.class);
         mIsPrimaryUser = mUserManager.isPrimaryUser();
+        int user = ActivityManager.getCurrentUser();
+        mUserIsUnlocked.put(user, mUserManager.isUserUnlocked(user));
         mDevicePolicyManager = context.getSystemService(DevicePolicyManager.class);
         mLogoutEnabled = mDevicePolicyManager.isLogoutEnabled();
         updateAirplaneModeState();
@@ -1707,6 +1742,19 @@
     }
 
     /**
+     * If a user is encrypted or not.
+     * This is NOT related to the lock screen being visible or not.
+     *
+     * @param userId The user.
+     * @return {@code true} when encrypted.
+     * @see UserManager#isUserUnlocked()
+     * @see Intent#ACTION_USER_UNLOCKED
+     */
+    public boolean isUserUnlocked(int userId) {
+        return mUserIsUnlocked.get(userId);
+    }
+
+    /**
      * Called whenever passive authentication is requested or aborted by a sensor.
      *
      * @param active If the interrupt started or ended.
@@ -1884,9 +1932,10 @@
      * If face hardware is available, user has enrolled and enabled auth via setting.
      */
     public boolean isFaceAuthEnabledForUser(int userId) {
-        return mFaceManager != null && mFaceManager.isHardwareDetected()
+        // TODO(b/140034352)
+        return whitelistIpcs(() -> mFaceManager != null && mFaceManager.isHardwareDetected()
                 && mFaceManager.hasEnrolledTemplates(userId)
-                && mFaceSettingEnabledForUser.get(userId);
+                && mFaceSettingEnabledForUser.get(userId));
     }
 
     private void stopListeningForFingerprint() {
@@ -2294,7 +2343,7 @@
     }
 
     private boolean resolveNeedsSlowUnlockTransition() {
-        if (mUserManager.isUserUnlocked(getCurrentUser())) {
+        if (isUserUnlocked(getCurrentUser())) {
             return false;
         }
         Intent homeIntent = new Intent(Intent.ACTION_MAIN)
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index 08691ec..1edb57e 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -34,13 +34,14 @@
     // list of "ABC", etc per digit, starting with '0'
     static String sKlondike[];
 
+    private final TextView mDigitText;
+    private final TextView mKlondikeText;
+    private final LockPatternUtils mLockPatternUtils;
+    private final PowerManager mPM;
+
     private int mDigit = -1;
     private int mTextViewResId;
     private PasswordTextView mTextView;
-    private TextView mDigitText;
-    private TextView mKlondikeText;
-    private boolean mEnableHaptics;
-    private PowerManager mPM;
 
     private View.OnClickListener mListener = new View.OnClickListener() {
         @Override
@@ -90,8 +91,7 @@
         setOnClickListener(mListener);
         setOnHoverListener(new LiftToActivateListener(context));
 
-        mEnableHaptics = new LockPatternUtils(context).isTactileFeedbackEnabled();
-
+        mLockPatternUtils = new LockPatternUtils(context);
         mPM = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
@@ -162,7 +162,7 @@
 
     // Cause a VIRTUAL_KEY vibration
     public void doHapticKeyClick() {
-        if (mEnableHaptics) {
+        if (mLockPatternUtils.isTactileFeedbackEnabled()) {
             performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
                     HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING
                     | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index ffa69fa..ce61a00 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -19,6 +19,7 @@
 import static android.app.StatusBarManager.DISABLE_NONE;
 import static android.provider.Settings.System.SHOW_BATTERY_PERCENT;
 
+import static com.android.systemui.DejankUtils.whitelistIpcs;
 import static com.android.systemui.util.SysuiLifecycle.viewAttachLifecycle;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -382,9 +383,10 @@
 
     private void updateShowPercent() {
         final boolean showing = mBatteryPercentView != null;
-        final boolean systemSetting = 0 != Settings.System
+        // TODO(b/140051051)
+        final boolean systemSetting = 0 != whitelistIpcs(() -> Settings.System
                 .getIntForUser(getContext().getContentResolver(),
-                SHOW_BATTERY_PERCENT, 0, mUser);
+                SHOW_BATTERY_PERCENT, 0, mUser));
 
         if ((mShowPercentAvailable && systemSetting && mShowPercentMode != MODE_OFF)
                 || mShowPercentMode == MODE_ON || mShowPercentMode == MODE_ESTIMATE) {
diff --git a/packages/SystemUI/src/com/android/systemui/ContextComponentHelper.java b/packages/SystemUI/src/com/android/systemui/ContextComponentHelper.java
index 8fabe7a..62826d8 100644
--- a/packages/SystemUI/src/com/android/systemui/ContextComponentHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ContextComponentHelper.java
@@ -16,10 +16,12 @@
 
 package com.android.systemui;
 
+import android.app.Service;
+
 /**
  * Interface necessary to make Dagger happy. See {@link ContextComponentResolver}.
  */
 public interface ContextComponentHelper {
     /** Turns a classname into an instance of the class or returns null. */
-    <T> T resolve(String className);
+    Service resolveService(String className);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/ContextComponentResolver.java b/packages/SystemUI/src/com/android/systemui/ContextComponentResolver.java
index 09bccd9..e8f0196 100644
--- a/packages/SystemUI/src/com/android/systemui/ContextComponentResolver.java
+++ b/packages/SystemUI/src/com/android/systemui/ContextComponentResolver.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui;
 
+import android.app.Service;
+
 import java.util.Map;
 
 import javax.inject.Inject;
@@ -25,21 +27,26 @@
  * Used during Service and Activity instantiation to make them injectable.
  */
 public class ContextComponentResolver implements ContextComponentHelper {
-    private final Map<Class<?>, Provider<Object>> mCreators;
+    private final Map<Class<?>, Provider<Service>> mServiceCreators;
 
     @Inject
-    ContextComponentResolver(Map<Class<?>, Provider<Object>> creators) {
-        mCreators = creators;
+    ContextComponentResolver(
+            Map<Class<?>, Provider<Service>> serviceCreators) {
+        mServiceCreators = serviceCreators;
     }
 
     /**
-     * Looks up the class name to see if Dagger has an instance of it.
+     * Looks up the Service class name to see if Dagger has an instance of it.
      */
     @Override
-    public <T> T resolve(String className) {
-        for (Map.Entry<Class<?>, Provider<Object>> p : mCreators.entrySet()) {
+    public Service resolveService(String className) {
+        return resolve(className, mServiceCreators);
+    }
+
+    private <T> T resolve(String className, Map<Class<?>, Provider<T>> creators) {
+        for (Map.Entry<Class<?>, Provider<T>> p : creators.entrySet()) {
             if (p.getKey().getName().equals(className)) {
-                return (T) p.getValue().get();
+                return p.getValue().get();
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/DejankUtils.java b/packages/SystemUI/src/com/android/systemui/DejankUtils.java
index bec8820..97578e1 100644
--- a/packages/SystemUI/src/com/android/systemui/DejankUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/DejankUtils.java
@@ -16,39 +16,200 @@
 
 package com.android.systemui;
 
+import static android.os.IBinder.FLAG_ONEWAY;
+
+import static com.android.settingslib.utils.ThreadUtils.isMainThread;
+
+import android.annotation.MainThread;
+import android.os.Binder;
+import android.os.Binder.ProxyTransactListener;
+import android.os.Build;
 import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.StrictMode;
+import android.os.SystemProperties;
 import android.view.Choreographer;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.util.Assert;
 
 import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Stack;
+import java.util.function.Supplier;
 
 /**
  * Utility class for methods used to dejank the UI.
  */
 public class DejankUtils {
 
+    public static final boolean STRICT_MODE_ENABLED = Build.IS_ENG
+            || SystemProperties.getBoolean("persist.sysui.strictmode", false);
     private static final Choreographer sChoreographer = Choreographer.getInstance();
     private static final Handler sHandler = new Handler();
     private static final ArrayList<Runnable> sPendingRunnables = new ArrayList<>();
+    private static Stack<String> sBlockingIpcs = new Stack<>();
+    private static boolean sTemporarilyIgnoreStrictMode;
+    private static final HashSet<String> sWhitelistedFrameworkClasses = new HashSet<>();
+    private static final Object sLock = new Object();
+    private static final ProxyTransactListener sProxy = new ProxyTransactListener() {
+        @Override
+        public Object onTransactStarted(IBinder binder, int transactionCode, int flags) {
+            synchronized (sLock) {
+                if ((flags & FLAG_ONEWAY) == FLAG_ONEWAY || sBlockingIpcs.empty()
+                        || !isMainThread() || sTemporarilyIgnoreStrictMode) {
+                    return null;
+                }
+
+                try {
+                    String description = binder.getInterfaceDescriptor();
+                    if (sWhitelistedFrameworkClasses.contains(description)) {
+                        return null;
+                    }
+                } catch (RemoteException e) {
+                    e.printStackTrace();
+                }
+
+                StrictMode.noteSlowCall("IPC detected on critical path: " + sBlockingIpcs.peek());
+                return null;
+            }
+        }
+
+        @Override
+        public Object onTransactStarted(IBinder binder, int transactionCode) {
+            return null;
+        }
+
+        @Override
+        public void onTransactEnded(Object o) {
+
+        }
+    };
 
     /**
      * Only for testing.
      */
     private static boolean sImmediate;
 
-    private static final Runnable sAnimationCallbackRunnable = new Runnable() {
-        @Override
-        public void run() {
-            for (int i = 0; i < sPendingRunnables.size(); i++) {
-                sHandler.post(sPendingRunnables.get(i));
-            }
-            sPendingRunnables.clear();
+    static {
+        if (STRICT_MODE_ENABLED) {
+            // Common IPCs that are ok to block the main thread.
+            sWhitelistedFrameworkClasses.add("android.view.IWindowSession");
+            sWhitelistedFrameworkClasses.add("com.android.internal.policy.IKeyguardStateCallback");
+            sWhitelistedFrameworkClasses.add("android.os.IPowerManager");
+            sWhitelistedFrameworkClasses.add("com.android.internal.statusbar.IStatusBarService");
+
+            Binder.setProxyTransactListener(sProxy);
+            StrictMode.ThreadPolicy.Builder builder = new StrictMode.ThreadPolicy.Builder()
+                    .detectCustomSlowCalls()
+                    .penaltyFlashScreen()
+                    .penaltyLog();
+            StrictMode.setThreadPolicy(builder.build());
         }
+    }
+
+    private static final Runnable sAnimationCallbackRunnable = () -> {
+        for (int i = 0; i < sPendingRunnables.size(); i++) {
+            sHandler.post(sPendingRunnables.get(i));
+        }
+        sPendingRunnables.clear();
     };
 
     /**
+     * Enable blocking-binder-call {@link StrictMode} for a {@link Runnable}.
+     *
+     * @param runnable Target.
+     */
+    @MainThread
+    public static void detectBlockingIpcs(Runnable runnable) {
+        if (STRICT_MODE_ENABLED && sBlockingIpcs.empty()) {
+            synchronized (sLock) {
+                sBlockingIpcs.push("detectBlockingIpcs");
+                try {
+                    runnable.run();
+                } finally {
+                    sBlockingIpcs.pop();
+                }
+            }
+        } else {
+            runnable.run();
+        }
+    }
+
+    /**
+     * Enable blocking-binder-call {@link StrictMode}.
+     *
+     * @param tag A key.
+     * @see #detectBlockingIpcs(Runnable)
+     */
+    @MainThread
+    public static void startDetectingBlockingIpcs(String tag) {
+        if (STRICT_MODE_ENABLED) {
+            synchronized (sLock) {
+                sBlockingIpcs.push(tag);
+            }
+        }
+    }
+
+    /**
+     * Stop IPC detection for a specific tag.
+     *
+     * @param tag The key.
+     * @see #startDetectingBlockingIpcs(String)
+     */
+    @MainThread
+    public static void stopDetectingBlockingIpcs(String tag) {
+        if (STRICT_MODE_ENABLED) {
+            synchronized (sLock) {
+                sBlockingIpcs.remove(tag);
+            }
+        }
+    }
+
+    /**
+     * Temporarily ignore blocking binder calls for contents of this {@link Runnable}.
+     *
+     * @param runnable Target.
+     */
+    @MainThread
+    public static void whitelistIpcs(Runnable runnable) {
+        if (STRICT_MODE_ENABLED && !sTemporarilyIgnoreStrictMode) {
+            synchronized (sLock) {
+                sTemporarilyIgnoreStrictMode = true;
+                try {
+                    runnable.run();
+                } finally {
+                    sTemporarilyIgnoreStrictMode = false;
+                }
+            }
+        } else {
+            runnable.run();
+        }
+    }
+
+    /**
+     * @see #whitelistIpcs(Runnable)
+     */
+    @MainThread
+    public static <T> T whitelistIpcs(Supplier<T> supplier) {
+        if (STRICT_MODE_ENABLED && !sTemporarilyIgnoreStrictMode) {
+            synchronized (sLock) {
+                sTemporarilyIgnoreStrictMode = true;
+                final T val;
+                try {
+                    val = supplier.get();
+                } finally {
+                    sTemporarilyIgnoreStrictMode = false;
+                }
+                return val;
+            }
+        } else {
+            return supplier.get();
+        }
+    }
+
+    /**
      * Executes {@code r} after performTraversals. Use this do to CPU heavy work for which the
      * timing is not critical for animation. The work is then scheduled at the same time
      * RenderThread is doing its thing, leading to better parallelization.
diff --git a/packages/SystemUI/src/com/android/systemui/ServiceBinder.java b/packages/SystemUI/src/com/android/systemui/ServiceBinder.java
index 6282c6e..131a0f8 100644
--- a/packages/SystemUI/src/com/android/systemui/ServiceBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/ServiceBinder.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui;
 
+import android.app.Service;
+
 import com.android.systemui.doze.DozeService;
 
 import dagger.Binds;
@@ -36,6 +38,5 @@
     @Binds
     @IntoMap
     @ClassKey(DozeService.class)
-    public abstract Object bindDozeService(DozeService service);
-
+    public abstract Service bindDozeService(DozeService service);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java
index 00ae992..6a59fa1 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java
@@ -18,16 +18,25 @@
 
 import android.app.Application;
 import android.app.Service;
+import android.content.ContentProvider;
+import android.content.Context;
 import android.content.Intent;
 
-import androidx.core.app.CoreComponentFactory;
+import androidx.annotation.NonNull;
+import androidx.core.app.AppComponentFactory;
 
 import javax.inject.Inject;
 
 /**
  * Implementation of AppComponentFactory that injects into constructors.
+ *
+ * This class sets up dependency injection when creating our application.
+ *
+ * Services support dependency injection into their constructors.
+ *
+ * ContentProviders support injection into member variables - _not_ constructors.
  */
-public class SystemUIAppComponentFactory extends CoreComponentFactory {
+public class SystemUIAppComponentFactory extends AppComponentFactory {
 
     @Inject
     public ContextComponentHelper mComponentHelper;
@@ -36,12 +45,14 @@
         super();
     }
 
+    @NonNull
     @Override
-    public Application instantiateApplication(ClassLoader cl, String className)
+    public Application instantiateApplicationCompat(
+            @NonNull ClassLoader cl, @NonNull String className)
             throws InstantiationException, IllegalAccessException, ClassNotFoundException {
-        Application app = super.instantiateApplication(cl, className);
-        if (app instanceof SystemUIApplication) {
-            ((SystemUIApplication) app).setContextAvailableCallback(
+        Application app = super.instantiateApplicationCompat(cl, className);
+        if (app instanceof ContextProvider) {
+            ((ContextProvider) app).setContextAvailableCallback(
                     context -> {
                         SystemUIFactory.createFromConfig(context);
                         SystemUIFactory.getInstance().getRootComponent().inject(
@@ -53,24 +64,43 @@
         return app;
     }
 
+    @NonNull
     @Override
-    public Service instantiateService(ClassLoader cl, String className, Intent intent)
+    public ContentProvider instantiateProviderCompat(
+            @NonNull ClassLoader cl, @NonNull String className)
             throws InstantiationException, IllegalAccessException, ClassNotFoundException {
-        Service service = mComponentHelper.resolve(className);
-        if (service != null) {
-            return checkCompatWrapper(service);
+
+        ContentProvider contentProvider = super.instantiateProviderCompat(cl, className);
+        if (contentProvider instanceof ContextProvider) {
+            ((ContextProvider) contentProvider).setContextAvailableCallback(
+                    context -> {
+                        SystemUIFactory.createFromConfig(context);
+                        SystemUIFactory.getInstance().getRootComponent().inject(
+                                contentProvider);
+                    }
+            );
         }
-        return super.instantiateService(cl, className, intent);
+
+        return contentProvider;
     }
 
-    static <T> T checkCompatWrapper(T obj) {
-        if (obj instanceof CompatWrapped) {
-            T wrapper = (T) ((CompatWrapped) obj).getWrapper();
-            if (wrapper != null) {
-                return wrapper;
-            }
+    @NonNull
+    @Override
+    public Service instantiateServiceCompat(
+            @NonNull ClassLoader cl, @NonNull String className, Intent intent)
+            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
+        Service service = mComponentHelper.resolveService(className);
+        if (service != null) {
+            return service;
         }
+        return super.instantiateServiceCompat(cl, className, intent);
+    }
 
-        return obj;
+    interface ContextAvailableCallback {
+        void onContextAvailable(Context context);
+    }
+
+    interface ContextProvider {
+        void setContextAvailableCallback(ContextAvailableCallback callback);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index f8449ad..aafc67e 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -48,7 +48,8 @@
 /**
  * Application class for SystemUI.
  */
-public class SystemUIApplication extends Application implements SysUiServiceProvider {
+public class SystemUIApplication extends Application implements SysUiServiceProvider,
+        SystemUIAppComponentFactory.ContextProvider {
 
     public static final String TAG = "SystemUIService";
     private static final boolean DEBUG = false;
@@ -60,7 +61,7 @@
     private boolean mServicesStarted;
     private boolean mBootCompleted;
     private final Map<Class<?>, Object> mComponents = new HashMap<>();
-    private ContextAvailableCallback mContextAvailableCallback;
+    private SystemUIAppComponentFactory.ContextAvailableCallback mContextAvailableCallback;
 
     @Override
     public void onCreate() {
@@ -74,7 +75,6 @@
         // the theme set there.
         setTheme(R.style.Theme_SystemUI);
 
-
         if (Process.myUserHandle().equals(UserHandle.SYSTEM)) {
             IntentFilter bootCompletedFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
             bootCompletedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
@@ -291,11 +291,10 @@
         return mServices;
     }
 
-    void setContextAvailableCallback(ContextAvailableCallback callback) {
+    @Override
+    public void setContextAvailableCallback(
+            SystemUIAppComponentFactory.ContextAvailableCallback callback) {
         mContextAvailableCallback = callback;
     }
 
-    interface ContextAvailableCallback {
-        void onContextAvailable(Context context);
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index b67d7df..39617ec 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -24,13 +24,13 @@
 import android.util.Log;
 import android.view.ViewGroup;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.colorextraction.ColorExtractor.GradientColors;
 import com.android.internal.util.function.TriConsumer;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.keyguard.DismissCallbackRegistry;
-import com.android.systemui.model.SysUiState;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -70,6 +70,10 @@
     }
 
     public static void createFromConfig(Context context) {
+        if (mFactory != null) {
+            return;
+        }
+
         final String clsName = context.getString(R.string.config_systemUIFactoryComponent);
         if (clsName == null || clsName.length() == 0) {
             throw new RuntimeException("No SystemUIFactory component configured");
@@ -86,6 +90,11 @@
         }
     }
 
+    @VisibleForTesting
+    static void cleanup() {
+        mFactory = null;
+    }
+
     public SystemUIFactory() {}
 
     private void init(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIRootComponent.java b/packages/SystemUI/src/com/android/systemui/SystemUIRootComponent.java
index f18c8b2..ad04f18 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIRootComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIRootComponent.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui;
 
+import android.content.ContentProvider;
+
 import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
 
 import com.android.systemui.fragments.FragmentService;
@@ -76,7 +78,12 @@
     boolean allowNotificationLongPressName();
 
     /**
-     * Injects into the supplied argument.
+     * Member injection into the supplied argument.
      */
     void inject(SystemUIAppComponentFactory factory);
+
+    /**
+     * Member injection into the supplied argument.
+     */
+    void inject(ContentProvider contentProvider);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
index 1e20b99..7a9feb7 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.assist;
 
+import static com.android.systemui.DejankUtils.whitelistIpcs;
+
 import android.app.ActivityManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -368,8 +370,9 @@
         long currentTimestamp = SystemClock.uptimeMillis();
         mLearningTimeElapsed += currentTimestamp - mLastLearningTimestamp;
         mLastLearningTimestamp = currentTimestamp;
-        Settings.Secure.putLong(
-                mContext.getContentResolver(), LEARNING_TIME_ELAPSED_KEY, mLearningTimeElapsed);
+        // TODO(b/140034473)
+        whitelistIpcs(() -> Settings.Secure.putLong(
+                mContext.getContentResolver(), LEARNING_TIME_ELAPSED_KEY, mLearningTimeElapsed));
 
         mIsLearned =
                 mLearningCount >= getLearningCount() || mLearningTimeElapsed >= getLearningTimeMs();
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index ac32d4d..c4feac1 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -1,5 +1,7 @@
 package com.android.systemui.assist;
 
+import static com.android.systemui.DejankUtils.whitelistIpcs;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
@@ -374,7 +376,8 @@
     }
 
     public boolean canVoiceAssistBeLaunchedFromKeyguard() {
-        return mAssistUtils.activeServiceSupportsLaunchFromKeyguard();
+        // TODO(b/140051519)
+        return whitelistIpcs(() -> mAssistUtils.activeServiceSupportsLaunchFromKeyguard());
     }
 
     public ComponentName getVoiceInteractorComponentName() {
@@ -442,7 +445,8 @@
     }
 
     public void onLockscreenShown() {
-        mAssistUtils.onLockscreenShown();
+        // TODO(b/140052478)
+        whitelistIpcs(mAssistUtils::onLockscreenShown);
     }
 
     public long getAssistHandleShowAndGoRemainingDurationMs() {
diff --git a/packages/SystemUI/src/com/android/systemui/assist/PhenotypeHelper.java b/packages/SystemUI/src/com/android/systemui/assist/PhenotypeHelper.java
index b3f57af..c21a717 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/PhenotypeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/PhenotypeHelper.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.assist;
 
+import static com.android.systemui.DejankUtils.whitelistIpcs;
+
 import android.provider.DeviceConfig;
 
 import androidx.annotation.Nullable;
@@ -27,20 +29,24 @@
     public PhenotypeHelper() {}
 
     public long getLong(String name, long defaultValue) {
-        return DeviceConfig.getLong(DeviceConfig.NAMESPACE_SYSTEMUI, name, defaultValue);
+        return whitelistIpcs(() ->
+                DeviceConfig.getLong(DeviceConfig.NAMESPACE_SYSTEMUI, name, defaultValue));
     }
 
     public int getInt(String name, int defaultValue) {
-        return DeviceConfig.getInt(DeviceConfig.NAMESPACE_SYSTEMUI, name, defaultValue);
+        return whitelistIpcs(() ->
+                DeviceConfig.getInt(DeviceConfig.NAMESPACE_SYSTEMUI, name, defaultValue));
     }
 
     @Nullable
     public String getString(String name, @Nullable String defaultValue) {
-        return DeviceConfig.getString(DeviceConfig.NAMESPACE_SYSTEMUI, name, defaultValue);
+        return whitelistIpcs(() ->
+                DeviceConfig.getString(DeviceConfig.NAMESPACE_SYSTEMUI, name, defaultValue));
     }
 
     public boolean getBoolean(String name, boolean defaultValue) {
-        return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, name, defaultValue);
+        return whitelistIpcs(() ->
+                DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, name, defaultValue));
     }
 
     public void addOnPropertiesChangedListener(
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/BiometricDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/ui/BiometricDialogView.java
index 2b4dde5..2904755 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/BiometricDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/BiometricDialogView.java
@@ -18,8 +18,14 @@
 
 import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ValueAnimator;
+import android.annotation.IntDef;
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
+import android.graphics.Outline;
 import android.graphics.PixelFormat;
 import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
@@ -38,6 +44,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewOutlineProvider;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
@@ -71,6 +78,7 @@
     public static final String KEY_ERROR_TEXT_STRING = "key_error_text_string";
     public static final String KEY_ERROR_TEXT_IS_TEMPORARY = "key_error_text_is_temporary";
     public static final String KEY_ERROR_TEXT_COLOR = "key_error_text_color";
+    public static final String KEY_DIALOG_SIZE = "key_dialog_size";
 
     private static final int ANIMATION_DURATION_SHOW = 250; // ms
     private static final int ANIMATION_DURATION_AWAY = 350; // ms
@@ -83,8 +91,18 @@
     protected static final int STATE_PENDING_CONFIRMATION = 3;
     protected static final int STATE_AUTHENTICATED = 4;
 
-    @VisibleForTesting
-    final WakefulnessLifecycle mWakefulnessLifecycle;
+    // Dialog layout/animation
+    private static final int IMPLICIT_Y_PADDING = 16; // dp
+    private static final int GROW_DURATION = 150; // ms
+    private static final int TEXT_ANIMATE_DISTANCE = 32; // dp
+    @VisibleForTesting static final int SIZE_UNKNOWN = 0;
+    @VisibleForTesting static final int SIZE_SMALL = 1;
+    @VisibleForTesting static final int SIZE_GROWING = 2;
+    @VisibleForTesting static final int SIZE_BIG = 3;
+    @IntDef({SIZE_UNKNOWN, SIZE_SMALL, SIZE_GROWING, SIZE_BIG})
+    @interface DialogSize {}
+
+    @VisibleForTesting final WakefulnessLifecycle mWakefulnessLifecycle;
     private final AccessibilityManager mAccessibilityManager;
     private final IBinder mWindowToken = new Binder();
     private final Interpolator mLinearOutSlowIn;
@@ -95,25 +113,18 @@
     private final int mErrorColor;
     private final float mDialogWidth;
     protected final DialogViewCallback mCallback;
+    private final DialogOutlineProvider mOutlineProvider = new DialogOutlineProvider();
 
     protected final ViewGroup mLayout;
     protected final LinearLayout mDialog;
-    @VisibleForTesting
-    final TextView mTitleText;
-    @VisibleForTesting
-    final TextView mSubtitleText;
-    @VisibleForTesting
-    final TextView mDescriptionText;
-    @VisibleForTesting
-    final ImageView mBiometricIcon;
-    @VisibleForTesting
-    final TextView mErrorText;
-    @VisibleForTesting
-    final Button mPositiveButton;
-    @VisibleForTesting
-    final Button mNegativeButton;
-    @VisibleForTesting
-    final Button mTryAgainButton;
+    @VisibleForTesting final TextView mTitleText;
+    @VisibleForTesting final TextView mSubtitleText;
+    @VisibleForTesting final TextView mDescriptionText;
+    @VisibleForTesting final ImageView mBiometricIcon;
+    @VisibleForTesting final TextView mErrorText;
+    @VisibleForTesting final Button mPositiveButton;
+    @VisibleForTesting final Button mNegativeButton;
+    @VisibleForTesting final Button mTryAgainButton;
 
     protected final int mTextColor;
 
@@ -126,6 +137,8 @@
     private boolean mSkipIntro;
     protected boolean mRequireConfirmation;
     private int mUserId; // used to determine if we should show work background
+    private @DialogSize int mSize;
+    private float mIconOriginalY;
 
     private boolean mCompletedAnimatingIn;
     private boolean mPendingDismissDialog;
@@ -137,6 +150,7 @@
     protected abstract boolean shouldGrayAreaDismissDialog();
     protected abstract void handleResetMessage();
     protected abstract void updateIcon(int oldState, int newState);
+    protected abstract boolean supportsSmallDialog();
 
     private final Runnable mShowAnimationRunnable = new Runnable() {
         @Override
@@ -166,6 +180,30 @@
                 }
             };
 
+    private final class DialogOutlineProvider extends ViewOutlineProvider {
+
+        float mY;
+
+        @Override
+        public void getOutline(View view, Outline outline) {
+            outline.setRoundRect(
+                    0 /* left */,
+                    (int) mY, /* top */
+                    mDialog.getWidth() /* right */,
+                    mDialog.getBottom(), /* bottom */
+                    getResources().getDimension(R.dimen.biometric_dialog_corner_size));
+        }
+
+        int calculateSmall() {
+            final float padding = Utils.dpToPixels(mContext, IMPLICIT_Y_PADDING);
+            return mDialog.getHeight() - mBiometricIcon.getHeight() - 2 * (int) padding;
+        }
+
+        void setOutlineY(float y) {
+            mY = y;
+        }
+    }
+
     protected Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
@@ -346,7 +384,6 @@
         mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
 
         final ImageView backgroundView = mLayout.findViewById(R.id.background);
-
         if (mUserManager.isManagedProfile(mUserId)) {
             final Drawable image = getResources().getDrawable(R.drawable.work_challenge_background,
                     mContext.getTheme());
@@ -428,6 +465,42 @@
         mSkipIntro = false;
     }
 
+    /**
+     * Do small/big layout here instead of onAttachedToWindow, since:
+     * 1) We need the big layout to be measured, etc for small -> big animation
+     * 2) We need the dialog measurements to know where to move the biometric icon to
+     *
+     * BiometricDialogView already sets the views to their default big state, so here we only
+     * need to hide the ones that are unnecessary.
+     */
+    @Override
+    public void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+
+        if (mIconOriginalY == 0) {
+            mIconOriginalY = mBiometricIcon.getY();
+        }
+
+        // UNKNOWN means size hasn't been set yet. First time we create the dialog.
+        // onLayout can happen when visibility of views change (during animation, etc).
+        if (getSize() != SIZE_UNKNOWN) {
+            // Probably not the cleanest way to do this, but since dialog is big by default,
+            // and small dialogs can persist across orientation changes, we need to set it to
+            // small size here again.
+            if (getSize() == SIZE_SMALL) {
+                updateSize(SIZE_SMALL);
+            }
+            return;
+        }
+
+        // If we don't require confirmation, show the small dialog first (until errors occur).
+        if (!requiresConfirmation() && supportsSmallDialog()) {
+            updateSize(SIZE_SMALL);
+        } else {
+            updateSize(SIZE_BIG);
+        }
+    }
+
     @Override
     public void onDetachedFromWindow() {
         super.onDetachedFromWindow();
@@ -435,6 +508,133 @@
         mWakefulnessLifecycle.removeObserver(mWakefulnessObserver);
     }
 
+    @VisibleForTesting
+    void updateSize(@DialogSize int newSize) {
+        final float padding = Utils.dpToPixels(mContext, IMPLICIT_Y_PADDING);
+        final float iconSmallPositionY = mDialog.getHeight() - mBiometricIcon.getHeight() - padding;
+
+        if (newSize == SIZE_SMALL) {
+            if (!supportsSmallDialog()) {
+                Log.e(TAG, "Small dialog unsupported");
+                return;
+            }
+
+            // These fields are required and/or always hold a spot on the UI, so should be set to
+            // INVISIBLE so they keep their position
+            mTitleText.setVisibility(View.INVISIBLE);
+            mErrorText.setVisibility(View.INVISIBLE);
+            mNegativeButton.setVisibility(View.INVISIBLE);
+
+            // These fields are optional, so set them to gone or invisible depending on their
+            // usage. If they're empty, they're already set to GONE in BiometricDialogView.
+            if (!TextUtils.isEmpty(mSubtitleText.getText())) {
+                mSubtitleText.setVisibility(View.INVISIBLE);
+            }
+            if (!TextUtils.isEmpty(mDescriptionText.getText())) {
+                mDescriptionText.setVisibility(View.INVISIBLE);
+            }
+
+            // Move the biometric icon to the small spot
+            mBiometricIcon.setY(iconSmallPositionY);
+
+            // Clip the dialog to the small size
+            mDialog.setOutlineProvider(mOutlineProvider);
+            mOutlineProvider.setOutlineY(mOutlineProvider.calculateSmall());
+
+            mDialog.setClipToOutline(true);
+            mDialog.invalidateOutline();
+
+            mSize = newSize;
+            announceAccessibilityEvent();
+        } else if (mSize == SIZE_SMALL && newSize == SIZE_BIG) {
+            mSize = SIZE_GROWING;
+
+            // Animate the outline
+            final ValueAnimator outlineAnimator =
+                    ValueAnimator.ofFloat(mOutlineProvider.calculateSmall(), 0);
+            outlineAnimator.addUpdateListener((animation) -> {
+                final float y = (float) animation.getAnimatedValue();
+                mOutlineProvider.setOutlineY(y);
+                mDialog.invalidateOutline();
+            });
+
+            // Animate the icon back to original big position
+            final ValueAnimator iconAnimator =
+                    ValueAnimator.ofFloat(iconSmallPositionY, mIconOriginalY);
+            iconAnimator.addUpdateListener((animation) -> {
+                final float y = (float) animation.getAnimatedValue();
+                mBiometricIcon.setY(y);
+            });
+
+            // Animate the error text so it slides up with the icon
+            final ValueAnimator textSlideAnimator =
+                    ValueAnimator.ofFloat(Utils.dpToPixels(mContext, TEXT_ANIMATE_DISTANCE), 0);
+            textSlideAnimator.addUpdateListener((animation) -> {
+                final float y = (float) animation.getAnimatedValue();
+                mErrorText.setTranslationY(y);
+            });
+
+            // Opacity animator for things that should fade in (title, subtitle, details, negative
+            // button)
+            final ValueAnimator opacityAnimator = ValueAnimator.ofFloat(0, 1);
+            opacityAnimator.addUpdateListener((animation) -> {
+                final float opacity = (float) animation.getAnimatedValue();
+
+                // These fields are required and/or always hold a spot on the UI
+                mTitleText.setAlpha(opacity);
+                mErrorText.setAlpha(opacity);
+                mNegativeButton.setAlpha(opacity);
+                mTryAgainButton.setAlpha(opacity);
+
+                // These fields are optional, so only animate them if they're supposed to be showing
+                if (!TextUtils.isEmpty(mSubtitleText.getText())) {
+                    mSubtitleText.setAlpha(opacity);
+                }
+                if (!TextUtils.isEmpty(mDescriptionText.getText())) {
+                    mDescriptionText.setAlpha(opacity);
+                }
+            });
+
+            // Choreograph together
+            final AnimatorSet as = new AnimatorSet();
+            as.setDuration(GROW_DURATION);
+            as.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    super.onAnimationStart(animation);
+                    // Set the visibility of opacity-animating views back to VISIBLE
+                    mTitleText.setVisibility(View.VISIBLE);
+                    mErrorText.setVisibility(View.VISIBLE);
+                    mNegativeButton.setVisibility(View.VISIBLE);
+                    mTryAgainButton.setVisibility(View.VISIBLE);
+
+                    if (!TextUtils.isEmpty(mSubtitleText.getText())) {
+                        mSubtitleText.setVisibility(View.VISIBLE);
+                    }
+                    if (!TextUtils.isEmpty(mDescriptionText.getText())) {
+                        mDescriptionText.setVisibility(View.VISIBLE);
+                    }
+                }
+
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    super.onAnimationEnd(animation);
+                    mSize = SIZE_BIG;
+                }
+            });
+            as.play(outlineAnimator).with(iconAnimator).with(opacityAnimator)
+                    .with(textSlideAnimator);
+            as.start();
+        } else if (mSize == SIZE_BIG) {
+            mDialog.setClipToOutline(false);
+            mDialog.invalidateOutline();
+
+            mBiometricIcon.setY(mIconOriginalY);
+
+            mSize = newSize;
+        }
+    }
+
     private void setDismissesDialog(View v) {
         v.setClickable(true);
         v.setOnClickListener(v1 -> {
@@ -599,6 +799,12 @@
      */
     @Override
     public void onError(String error) {
+        // All error messages will cause the dialog to go from small -> big. Error messages
+        // are messages such as lockout, auth failed, etc.
+        if (mSize == SIZE_SMALL) {
+            updateSize(SIZE_BIG);
+        }
+
         updateState(STATE_ERROR);
         showTemporaryMessage(error);
         showTryAgainButton(false /* show */);
@@ -619,11 +825,16 @@
         bundle.putCharSequence(KEY_ERROR_TEXT_STRING, mErrorText.getText());
         bundle.putBoolean(KEY_ERROR_TEXT_IS_TEMPORARY, mHandler.hasMessages(MSG_RESET_MESSAGE));
         bundle.putInt(KEY_ERROR_TEXT_COLOR, mErrorText.getCurrentTextColor());
+        bundle.putInt(KEY_DIALOG_SIZE, mSize);
     }
 
     @Override
     public void restoreState(Bundle bundle) {
         mRestoredState = bundle;
+
+        // Keep in mind that this happens before onAttachedToWindow()
+        mSize = bundle.getInt(KEY_DIALOG_SIZE);
+
         final int tryAgainVisibility = bundle.getInt(KEY_TRY_AGAIN_VISIBILITY);
         mTryAgainButton.setVisibility(tryAgainVisibility);
         final int confirmVisibility = bundle.getInt(KEY_CONFIRM_VISIBILITY);
@@ -678,7 +889,28 @@
         mState = newState;
     }
 
+    protected @DialogSize int getSize() {
+        return mSize;
+    }
+
     protected void showTryAgainButton(boolean show) {
+        if (show && getSize() == SIZE_SMALL) {
+            // Do not call super, we will nicely animate the alpha together with the rest
+            // of the elements in here.
+            updateSize(SIZE_BIG);
+        } else {
+            if (show) {
+                mTryAgainButton.setVisibility(View.VISIBLE);
+            } else {
+                mTryAgainButton.setVisibility(View.GONE);
+                announceAccessibilityEvent();
+            }
+        }
+
+        if (show) {
+            mPositiveButton.setVisibility(View.GONE);
+            announceAccessibilityEvent();
+        }
     }
 
     protected void onDialogAnimatedIn() {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/FaceDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/ui/FaceDialogView.java
index bd87148..9e4fe24 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/FaceDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/FaceDialogView.java
@@ -16,24 +16,15 @@
 
 package com.android.systemui.biometrics.ui;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ValueAnimator;
 import android.content.Context;
-import android.graphics.Outline;
 import android.graphics.drawable.Animatable2;
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable;
 import android.hardware.biometrics.BiometricPrompt;
 import android.os.Bundle;
-import android.text.TextUtils;
-import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.View;
-import android.view.ViewOutlineProvider;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.R;
 import com.android.systemui.biometrics.DialogViewCallback;
 
@@ -45,23 +36,11 @@
 public class FaceDialogView extends BiometricDialogView {
 
     private static final String TAG = "FaceDialogView";
-    private static final String KEY_DIALOG_SIZE = "key_dialog_size";
+
     private static final String KEY_DIALOG_ANIMATED_IN = "key_dialog_animated_in";
 
     private static final int HIDE_DIALOG_DELAY = 500; // ms
-    private static final int IMPLICIT_Y_PADDING = 16; // dp
-    private static final int GROW_DURATION = 150; // ms
-    private static final int TEXT_ANIMATE_DISTANCE = 32; // dp
 
-    private static final int SIZE_UNKNOWN = 0;
-    @VisibleForTesting
-    static final int SIZE_SMALL = 1;
-    private static final int SIZE_GROWING = 2;
-    private static final int SIZE_BIG = 3;
-
-    private int mSize;
-    private float mIconOriginalY;
-    private DialogOutlineProvider mOutlineProvider = new DialogOutlineProvider();
     private IconController mIconController;
     private boolean mDialogAnimatedIn;
 
@@ -125,30 +104,6 @@
         }
     }
 
-    private final class DialogOutlineProvider extends ViewOutlineProvider {
-
-        float mY;
-
-        @Override
-        public void getOutline(View view, Outline outline) {
-            outline.setRoundRect(
-                    0 /* left */,
-                    (int) mY, /* top */
-                    mDialog.getWidth() /* right */,
-                    mDialog.getBottom(), /* bottom */
-                    getResources().getDimension(R.dimen.biometric_dialog_corner_size));
-        }
-
-        int calculateSmall() {
-            final float padding = dpToPixels(IMPLICIT_Y_PADDING);
-            return mDialog.getHeight() - mBiometricIcon.getHeight() - 2 * (int) padding;
-        }
-
-        void setOutlineY(float y) {
-            mY = y;
-        }
-    }
-
     private final Runnable mErrorToIdleAnimationRunnable = () -> {
         updateState(STATE_IDLE);
         mErrorText.setVisibility(View.INVISIBLE);
@@ -160,132 +115,9 @@
         mIconController = new IconController();
     }
 
-    @VisibleForTesting
-    void updateSize(int newSize) {
-        final float padding = dpToPixels(IMPLICIT_Y_PADDING);
-        final float iconSmallPositionY = mDialog.getHeight() - mBiometricIcon.getHeight() - padding;
-
-        if (newSize == SIZE_SMALL) {
-            // These fields are required and/or always hold a spot on the UI, so should be set to
-            // INVISIBLE so they keep their position
-            mTitleText.setVisibility(View.INVISIBLE);
-            mErrorText.setVisibility(View.INVISIBLE);
-            mNegativeButton.setVisibility(View.INVISIBLE);
-
-            // These fields are optional, so set them to gone or invisible depending on their
-            // usage. If they're empty, they're already set to GONE in BiometricDialogView.
-            if (!TextUtils.isEmpty(mSubtitleText.getText())) {
-                mSubtitleText.setVisibility(View.INVISIBLE);
-            }
-            if (!TextUtils.isEmpty(mDescriptionText.getText())) {
-                mDescriptionText.setVisibility(View.INVISIBLE);
-            }
-
-            // Move the biometric icon to the small spot
-            mBiometricIcon.setY(iconSmallPositionY);
-
-            // Clip the dialog to the small size
-            mDialog.setOutlineProvider(mOutlineProvider);
-            mOutlineProvider.setOutlineY(mOutlineProvider.calculateSmall());
-
-            mDialog.setClipToOutline(true);
-            mDialog.invalidateOutline();
-
-            mSize = newSize;
-            announceAccessibilityEvent();
-        } else if (mSize == SIZE_SMALL && newSize == SIZE_BIG) {
-            mSize = SIZE_GROWING;
-
-            // Animate the outline
-            final ValueAnimator outlineAnimator =
-                    ValueAnimator.ofFloat(mOutlineProvider.calculateSmall(), 0);
-            outlineAnimator.addUpdateListener((animation) -> {
-                final float y = (float) animation.getAnimatedValue();
-                mOutlineProvider.setOutlineY(y);
-                mDialog.invalidateOutline();
-            });
-
-            // Animate the icon back to original big position
-            final ValueAnimator iconAnimator =
-                    ValueAnimator.ofFloat(iconSmallPositionY, mIconOriginalY);
-            iconAnimator.addUpdateListener((animation) -> {
-                final float y = (float) animation.getAnimatedValue();
-                mBiometricIcon.setY(y);
-            });
-
-            // Animate the error text so it slides up with the icon
-            final ValueAnimator textSlideAnimator =
-                    ValueAnimator.ofFloat(dpToPixels(TEXT_ANIMATE_DISTANCE), 0);
-            textSlideAnimator.addUpdateListener((animation) -> {
-                final float y = (float) animation.getAnimatedValue();
-                mErrorText.setTranslationY(y);
-            });
-
-            // Opacity animator for things that should fade in (title, subtitle, details, negative
-            // button)
-            final ValueAnimator opacityAnimator = ValueAnimator.ofFloat(0, 1);
-            opacityAnimator.addUpdateListener((animation) -> {
-                final float opacity = (float) animation.getAnimatedValue();
-
-                // These fields are required and/or always hold a spot on the UI
-                mTitleText.setAlpha(opacity);
-                mErrorText.setAlpha(opacity);
-                mNegativeButton.setAlpha(opacity);
-                mTryAgainButton.setAlpha(opacity);
-
-                // These fields are optional, so only animate them if they're supposed to be showing
-                if (!TextUtils.isEmpty(mSubtitleText.getText())) {
-                    mSubtitleText.setAlpha(opacity);
-                }
-                if (!TextUtils.isEmpty(mDescriptionText.getText())) {
-                    mDescriptionText.setAlpha(opacity);
-                }
-            });
-
-            // Choreograph together
-            final AnimatorSet as = new AnimatorSet();
-            as.setDuration(GROW_DURATION);
-            as.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationStart(Animator animation) {
-                    super.onAnimationStart(animation);
-                    // Set the visibility of opacity-animating views back to VISIBLE
-                    mTitleText.setVisibility(View.VISIBLE);
-                    mErrorText.setVisibility(View.VISIBLE);
-                    mNegativeButton.setVisibility(View.VISIBLE);
-                    mTryAgainButton.setVisibility(View.VISIBLE);
-
-                    if (!TextUtils.isEmpty(mSubtitleText.getText())) {
-                        mSubtitleText.setVisibility(View.VISIBLE);
-                    }
-                    if (!TextUtils.isEmpty(mDescriptionText.getText())) {
-                        mDescriptionText.setVisibility(View.VISIBLE);
-                    }
-                }
-
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    super.onAnimationEnd(animation);
-                    mSize = SIZE_BIG;
-                }
-            });
-            as.play(outlineAnimator).with(iconAnimator).with(opacityAnimator)
-                    .with(textSlideAnimator);
-            as.start();
-        } else if (mSize == SIZE_BIG) {
-            mDialog.setClipToOutline(false);
-            mDialog.invalidateOutline();
-
-            mBiometricIcon.setY(mIconOriginalY);
-
-            mSize = newSize;
-        }
-    }
-
     @Override
     public void onSaveState(Bundle bundle) {
         super.onSaveState(bundle);
-        bundle.putInt(KEY_DIALOG_SIZE, mSize);
         bundle.putBoolean(KEY_DIALOG_ANIMATED_IN, mDialogAnimatedIn);
     }
 
@@ -300,57 +132,9 @@
     @Override
     public void restoreState(Bundle bundle) {
         super.restoreState(bundle);
-        // Keep in mind that this happens before onAttachedToWindow()
-        mSize = bundle.getInt(KEY_DIALOG_SIZE);
         mDialogAnimatedIn = bundle.getBoolean(KEY_DIALOG_ANIMATED_IN);
     }
 
-    /**
-     * Do small/big layout here instead of onAttachedToWindow, since:
-     * 1) We need the big layout to be measured, etc for small -> big animation
-     * 2) We need the dialog measurements to know where to move the biometric icon to
-     *
-     * BiometricDialogView already sets the views to their default big state, so here we only
-     * need to hide the ones that are unnecessary.
-     */
-    @Override
-    public void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-
-        if (mIconOriginalY == 0) {
-            mIconOriginalY = mBiometricIcon.getY();
-        }
-
-        // UNKNOWN means size hasn't been set yet. First time we create the dialog.
-        // onLayout can happen when visibility of views change (during animation, etc).
-        if (mSize != SIZE_UNKNOWN) {
-            // Probably not the cleanest way to do this, but since dialog is big by default,
-            // and small dialogs can persist across orientation changes, we need to set it to
-            // small size here again.
-            if (mSize == SIZE_SMALL) {
-                updateSize(SIZE_SMALL);
-            }
-            return;
-        }
-
-        // If we don't require confirmation, show the small dialog first (until errors occur).
-        if (!requiresConfirmation()) {
-            updateSize(SIZE_SMALL);
-        } else {
-            updateSize(SIZE_BIG);
-        }
-    }
-
-    @Override
-    public void onError(String error) {
-        super.onError(error);
-        // All error messages will cause the dialog to go from small -> big. Error messages
-        // are messages such as lockout, auth failed, etc.
-        if (mSize == SIZE_SMALL) {
-            updateSize(SIZE_BIG);
-        }
-    }
-
     @Override
     public void onAuthenticationFailed(String message) {
         super.onAuthenticationFailed(message);
@@ -358,27 +142,6 @@
     }
 
     @Override
-    public void showTryAgainButton(boolean show) {
-        if (show && mSize == SIZE_SMALL) {
-            // Do not call super, we will nicely animate the alpha together with the rest
-            // of the elements in here.
-            updateSize(SIZE_BIG);
-        } else {
-            if (show) {
-                mTryAgainButton.setVisibility(View.VISIBLE);
-            } else {
-                mTryAgainButton.setVisibility(View.GONE);
-                announceAccessibilityEvent();
-            }
-        }
-
-        if (show) {
-            mPositiveButton.setVisibility(View.GONE);
-            announceAccessibilityEvent();
-        }
-    }
-
-    @Override
     protected int getHintStringResourceId() {
         return 0;
     }
@@ -462,6 +225,11 @@
     }
 
     @Override
+    protected boolean supportsSmallDialog() {
+        return true;
+    }
+
+    @Override
     public void onDialogAnimatedIn() {
         super.onDialogAnimatedIn();
         mDialogAnimatedIn = true;
@@ -475,19 +243,11 @@
 
     @Override
     protected boolean shouldGrayAreaDismissDialog() {
-        if (mSize == SIZE_SMALL) {
+        if (getSize() == SIZE_SMALL) {
             return false;
         }
         return true;
     }
 
-    private float dpToPixels(float dp) {
-        return dp * ((float) mContext.getResources().getDisplayMetrics().densityDpi
-                / DisplayMetrics.DENSITY_DEFAULT);
-    }
 
-    private float pixelsToDp(float pixels) {
-        return pixels / ((float) mContext.getResources().getDisplayMetrics().densityDpi
-                / DisplayMetrics.DENSITY_DEFAULT);
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/FingerprintDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/ui/FingerprintDialogView.java
index e597080..2925880 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/FingerprintDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/FingerprintDialogView.java
@@ -80,6 +80,11 @@
         }
     }
 
+    @Override
+    protected boolean supportsSmallDialog() {
+        return false;
+    }
+
     protected boolean shouldAnimateForTransition(int oldState, int newState) {
         if (newState == STATE_ERROR) {
             return true;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/Utils.java b/packages/SystemUI/src/com/android/systemui/biometrics/ui/Utils.java
new file mode 100644
index 0000000..028b1aa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/Utils.java
@@ -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 com.android.systemui.biometrics.ui;
+
+import android.content.Context;
+import android.util.DisplayMetrics;
+
+public class Utils {
+    static float dpToPixels(Context context, float dp) {
+        return dp * ((float) context.getResources().getDisplayMetrics().densityDpi
+                / DisplayMetrics.DENSITY_DEFAULT);
+    }
+
+    static float pixelsToDp(Context context, float pixels) {
+        return pixels / ((float) context.getResources().getDisplayMetrics().densityDpi
+                / DisplayMetrics.DENSITY_DEFAULT);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
index 4120334..efac147 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
@@ -35,6 +35,7 @@
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.util.AsyncSensorManager;
+import com.android.systemui.util.DeviceConfigProxy;
 
 import java.io.PrintWriter;
 
@@ -51,18 +52,23 @@
 public class FalsingManagerProxy implements FalsingManager {
 
     private FalsingManager mInternalFalsingManager;
-    private final Handler mMainHandler;
+    private DeviceConfig.OnPropertiesChangedListener mDeviceConfigListener;
+    private final DeviceConfigProxy mDeviceConfig;
     private boolean mBrightlineEnabled;
 
     @Inject
     FalsingManagerProxy(Context context, PluginManager pluginManager,
-            @Named(MAIN_HANDLER_NAME) Handler handler) {
-        mMainHandler = handler;
+            @Named(MAIN_HANDLER_NAME) Handler handler, DeviceConfigProxy deviceConfig) {
+        mDeviceConfig = deviceConfig;
+        mDeviceConfigListener =
+                properties -> onDeviceConfigPropertiesChanged(context, properties.getNamespace());
         setupFalsingManager(context);
-        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
-                command -> mMainHandler.post(command),
-                properties -> onDeviceConfigPropertiesChanged(context, properties.getNamespace())
+        mDeviceConfig.addOnPropertiesChangedListener(
+                DeviceConfig.NAMESPACE_SYSTEMUI,
+                handler::post,
+                mDeviceConfigListener
         );
+
         final PluginListener<FalsingPlugin> mPluginListener = new PluginListener<FalsingPlugin>() {
             public void onPluginConnected(FalsingPlugin plugin, Context context) {
                 FalsingManager pluginFalsingManager = plugin.getFalsingManager(context);
@@ -91,9 +97,8 @@
     /**
      * Chooses the FalsingManager implementation.
      */
-    @VisibleForTesting
-    public void setupFalsingManager(Context context) {
-        boolean brightlineEnabled = DeviceConfig.getBoolean(
+    private void setupFalsingManager(Context context) {
+        boolean brightlineEnabled = mDeviceConfig.getBoolean(
                 DeviceConfig.NAMESPACE_SYSTEMUI, BRIGHTLINE_FALSING_MANAGER_ENABLED, true);
         if (brightlineEnabled == mBrightlineEnabled && mInternalFalsingManager != null) {
             return;
@@ -109,10 +114,10 @@
             mInternalFalsingManager = new BrightLineFalsingManager(
                     new FalsingDataProvider(context.getResources().getDisplayMetrics()),
                     Dependency.get(AsyncSensorManager.class),
-                    KeyguardUpdateMonitor.getInstance(context)
+                    KeyguardUpdateMonitor.getInstance(context),
+                    mDeviceConfig
             );
         }
-
     }
 
     /**
@@ -305,6 +310,7 @@
 
     @Override
     public void cleanup() {
+        mDeviceConfig.removeOnPropertiesChangedListener(mDeviceConfigListener);
         mInternalFalsingManager.cleanup();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
index 9e0b702..9e646b62 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
@@ -33,6 +33,7 @@
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.classifier.Classifier;
 import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.util.DeviceConfigProxy;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -88,7 +89,8 @@
     public BrightLineFalsingManager(
             FalsingDataProvider falsingDataProvider,
             SensorManager sensorManager,
-            KeyguardUpdateMonitor keyguardUpdateMonitor) {
+            KeyguardUpdateMonitor keyguardUpdateMonitor,
+            DeviceConfigProxy deviceConfigProxy) {
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mDataProvider = falsingDataProvider;
         mSensorManager = sensorManager;
@@ -96,15 +98,16 @@
 
         mMetricsLogger = new MetricsLogger();
         mClassifiers = new ArrayList<>();
-        DistanceClassifier distanceClassifier = new DistanceClassifier(mDataProvider);
-        ProximityClassifier proximityClassifier = new ProximityClassifier(distanceClassifier,
-                mDataProvider);
+        DistanceClassifier distanceClassifier =
+                new DistanceClassifier(mDataProvider, deviceConfigProxy);
+        ProximityClassifier proximityClassifier =
+                new ProximityClassifier(distanceClassifier, mDataProvider, deviceConfigProxy);
         mClassifiers.add(new PointerCountClassifier(mDataProvider));
         mClassifiers.add(new TypeClassifier(mDataProvider));
-        mClassifiers.add(new DiagonalClassifier(mDataProvider));
+        mClassifiers.add(new DiagonalClassifier(mDataProvider, deviceConfigProxy));
         mClassifiers.add(distanceClassifier);
         mClassifiers.add(proximityClassifier);
-        mClassifiers.add(new ZigZagClassifier(mDataProvider));
+        mClassifiers.add(new ZigZagClassifier(mDataProvider, deviceConfigProxy));
     }
 
     private void registerSensors() {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java
index cc66454..9c03b91 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java
@@ -23,6 +23,8 @@
 
 import android.provider.DeviceConfig;
 
+import com.android.systemui.util.DeviceConfigProxy;
+
 /**
  * False on swipes that are too close to 45 degrees.
  *
@@ -42,14 +44,14 @@
     private final float mHorizontalAngleRange;
     private final float mVerticalAngleRange;
 
-    DiagonalClassifier(FalsingDataProvider dataProvider) {
+    DiagonalClassifier(FalsingDataProvider dataProvider, DeviceConfigProxy deviceConfigProxy) {
         super(dataProvider);
 
-        mHorizontalAngleRange = DeviceConfig.getFloat(
+        mHorizontalAngleRange = deviceConfigProxy.getFloat(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 BRIGHTLINE_FALSING_DIAGONAL_HORIZONTAL_ANGLE_RANGE,
                 HORIZONTAL_ANGLE_RANGE);
-        mVerticalAngleRange = DeviceConfig.getFloat(
+        mVerticalAngleRange = deviceConfigProxy.getFloat(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 BRIGHTLINE_FALSING_DIAGONAL_VERTICAL_ANGLE_RANGE,
                 VERTICAL_ANGLE_RANGE);
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java
index a6a617d..0954f9e 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java
@@ -27,6 +27,8 @@
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 
+import com.android.systemui.util.DeviceConfigProxy;
+
 import java.util.List;
 
 /**
@@ -50,35 +52,35 @@
     private boolean mDistanceDirty;
     private DistanceVectors mCachedDistance;
 
-    DistanceClassifier(FalsingDataProvider dataProvider) {
+    DistanceClassifier(FalsingDataProvider dataProvider, DeviceConfigProxy deviceConfigProxy) {
         super(dataProvider);
 
-        mVelocityToDistanceMultiplier = DeviceConfig.getFloat(
+        mVelocityToDistanceMultiplier = deviceConfigProxy.getFloat(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 BRIGHTLINE_FALSING_DISTANCE_VELOCITY_TO_DISTANCE,
                 VELOCITY_TO_DISTANCE);
 
-        float horizontalFlingThresholdIn = DeviceConfig.getFloat(
+        float horizontalFlingThresholdIn = deviceConfigProxy.getFloat(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 BRIGHTLINE_FALSING_DISTANCE_HORIZONTAL_FLING_THRESHOLD_IN,
                 HORIZONTAL_FLING_THRESHOLD_DISTANCE_IN);
 
-        float verticalFlingThresholdIn = DeviceConfig.getFloat(
+        float verticalFlingThresholdIn = deviceConfigProxy.getFloat(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 BRIGHTLINE_FALSING_DISTANCE_VERTICAL_FLING_THRESHOLD_IN,
                 VERTICAL_FLING_THRESHOLD_DISTANCE_IN);
 
-        float horizontalSwipeThresholdIn = DeviceConfig.getFloat(
+        float horizontalSwipeThresholdIn = deviceConfigProxy.getFloat(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 BRIGHTLINE_FALSING_DISTANCE_HORIZONTAL_SWIPE_THRESHOLD_IN,
                 HORIZONTAL_SWIPE_THRESHOLD_DISTANCE_IN);
 
-        float verticalSwipeThresholdIn = DeviceConfig.getFloat(
+        float verticalSwipeThresholdIn = deviceConfigProxy.getFloat(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 BRIGHTLINE_FALSING_DISTANCE_VERTICAL_SWIPE_THRESHOLD_IN,
                 VERTICAL_SWIPE_THRESHOLD_DISTANCE_IN);
 
-        float screenFractionMaxDistance = DeviceConfig.getFloat(
+        float screenFractionMaxDistance = deviceConfigProxy.getFloat(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 BRIGHTLINE_FALSING_DISTANCE_SCREEN_FRACTION_MAX_DISTANCE,
                 SCREEN_FRACTION_MAX_DISTANCE);
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java
index 2644bf9..1827047 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java
@@ -24,6 +24,8 @@
 import android.provider.DeviceConfig;
 import android.view.MotionEvent;
 
+import com.android.systemui.util.DeviceConfigProxy;
+
 
 /**
  * False touch if proximity sensor is covered for more than a certain percentage of the gesture.
@@ -44,11 +46,11 @@
     private float mPercentNear;
 
     ProximityClassifier(DistanceClassifier distanceClassifier,
-            FalsingDataProvider dataProvider) {
+            FalsingDataProvider dataProvider, DeviceConfigProxy deviceConfigProxy) {
         super(dataProvider);
         this.mDistanceClassifier = distanceClassifier;
 
-        mPercentCoveredThreshold = DeviceConfig.getFloat(
+        mPercentCoveredThreshold = deviceConfigProxy.getFloat(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 BRIGHTLINE_FALSING_PROXIMITY_PERCENT_COVERED_THRESHOLD,
                 PERCENT_COVERED_THRESHOLD);
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java
index 82ae30a..a0da988 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java
@@ -25,6 +25,8 @@
 import android.provider.DeviceConfig;
 import android.view.MotionEvent;
 
+import com.android.systemui.util.DeviceConfigProxy;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -48,25 +50,25 @@
     private final float mMaxXSecondaryDeviance;
     private final float mMaxYSecondaryDeviance;
 
-    ZigZagClassifier(FalsingDataProvider dataProvider) {
+    ZigZagClassifier(FalsingDataProvider dataProvider, DeviceConfigProxy deviceConfigProxy) {
         super(dataProvider);
 
-        mMaxXPrimaryDeviance = DeviceConfig.getFloat(
+        mMaxXPrimaryDeviance = deviceConfigProxy.getFloat(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 BRIGHTLINE_FALSING_ZIGZAG_X_PRIMARY_DEVIANCE,
                 MAX_X_PRIMARY_DEVIANCE);
 
-        mMaxYPrimaryDeviance = DeviceConfig.getFloat(
+        mMaxYPrimaryDeviance = deviceConfigProxy.getFloat(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 BRIGHTLINE_FALSING_ZIGZAG_Y_PRIMARY_DEVIANCE,
                 MAX_Y_PRIMARY_DEVIANCE);
 
-        mMaxXSecondaryDeviance = DeviceConfig.getFloat(
+        mMaxXSecondaryDeviance = deviceConfigProxy.getFloat(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 BRIGHTLINE_FALSING_ZIGZAG_X_SECONDARY_DEVIANCE,
                 MAX_X_SECONDARY_DEVIANCE);
 
-        mMaxYSecondaryDeviance = DeviceConfig.getFloat(
+        mMaxYSecondaryDeviance = deviceConfigProxy.getFloat(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 BRIGHTLINE_FALSING_ZIGZAG_Y_SECONDARY_DEVIANCE,
                 MAX_Y_SECONDARY_DEVIANCE);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 36c3cc6..4016b59 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -25,6 +25,7 @@
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
+import static com.android.systemui.DejankUtils.whitelistIpcs;
 
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
@@ -643,26 +644,29 @@
 
         @Override
         public int getBouncerPromptReason() {
-            int currentUser = ActivityManager.getCurrentUser();
-            boolean trust = mTrustManager.isTrustUsuallyManaged(currentUser);
-            boolean biometrics = mUpdateMonitor.isUnlockingWithBiometricsPossible(currentUser);
-            boolean any = trust || biometrics;
-            KeyguardUpdateMonitor.StrongAuthTracker strongAuthTracker =
-                    mUpdateMonitor.getStrongAuthTracker();
-            int strongAuth = strongAuthTracker.getStrongAuthForUser(currentUser);
+            // TODO(b/140053364)
+            return whitelistIpcs(() -> {
+                int currentUser = ActivityManager.getCurrentUser();
+                boolean trust = mTrustManager.isTrustUsuallyManaged(currentUser);
+                boolean biometrics = mUpdateMonitor.isUnlockingWithBiometricsPossible(currentUser);
+                boolean any = trust || biometrics;
+                KeyguardUpdateMonitor.StrongAuthTracker strongAuthTracker =
+                        mUpdateMonitor.getStrongAuthTracker();
+                int strongAuth = strongAuthTracker.getStrongAuthForUser(currentUser);
 
-            if (any && !strongAuthTracker.hasUserAuthenticatedSinceBoot()) {
-                return KeyguardSecurityView.PROMPT_REASON_RESTART;
-            } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_TIMEOUT) != 0) {
-                return KeyguardSecurityView.PROMPT_REASON_TIMEOUT;
-            } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW) != 0) {
-                return KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN;
-            } else if (trust && (strongAuth & SOME_AUTH_REQUIRED_AFTER_USER_REQUEST) != 0) {
-                return KeyguardSecurityView.PROMPT_REASON_USER_REQUEST;
-            } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_LOCKOUT) != 0) {
-                return KeyguardSecurityView.PROMPT_REASON_AFTER_LOCKOUT;
-            }
-            return KeyguardSecurityView.PROMPT_REASON_NONE;
+                if (any && !strongAuthTracker.hasUserAuthenticatedSinceBoot()) {
+                    return KeyguardSecurityView.PROMPT_REASON_RESTART;
+                } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_TIMEOUT) != 0) {
+                    return KeyguardSecurityView.PROMPT_REASON_TIMEOUT;
+                } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW) != 0) {
+                    return KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN;
+                } else if (trust && (strongAuth & SOME_AUTH_REQUIRED_AFTER_USER_REQUEST) != 0) {
+                    return KeyguardSecurityView.PROMPT_REASON_USER_REQUEST;
+                } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_LOCKOUT) != 0) {
+                    return KeyguardSecurityView.PROMPT_REASON_AFTER_LOCKOUT;
+                }
+                return KeyguardSecurityView.PROMPT_REASON_NONE;
+            });
         }
 
         @Override
@@ -2172,18 +2176,21 @@
     }
 
     private void notifyDefaultDisplayCallbacks(boolean showing) {
-        int size = mKeyguardStateCallbacks.size();
-        for (int i = size - 1; i >= 0; i--) {
-            IKeyguardStateCallback callback = mKeyguardStateCallbacks.get(i);
-            try {
-                callback.onShowingStateChanged(showing);
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Failed to call onShowingStateChanged", e);
-                if (e instanceof DeadObjectException) {
-                    mKeyguardStateCallbacks.remove(callback);
+        // TODO(b/140053364)
+        whitelistIpcs(() -> {
+            int size = mKeyguardStateCallbacks.size();
+            for (int i = size - 1; i >= 0; i--) {
+                IKeyguardStateCallback callback = mKeyguardStateCallbacks.get(i);
+                try {
+                    callback.onShowingStateChanged(showing);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Failed to call onShowingStateChanged", e);
+                    if (e instanceof DeadObjectException) {
+                        mKeyguardStateCallbacks.remove(callback);
+                    }
                 }
             }
-        }
+        });
         updateInputRestrictedLocked();
         mUiOffloadThread.submit(() -> {
             mTrustManager.reportKeyguardShowingChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java b/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java
index 4571ef3..8c21dde 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs;
 
+import static com.android.systemui.DejankUtils.whitelistIpcs;
 import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
 
 import android.content.Context;
@@ -109,7 +110,8 @@
             return;
         }
         mListening = listening;
-        updateListeners();
+        // TODO(b/140053526)
+        whitelistIpcs(this::updateListeners);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index f1e9c87..37113cf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs;
 
+import static com.android.systemui.DejankUtils.whitelistIpcs;
 import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
 
 import android.content.Context;
@@ -164,7 +165,9 @@
     };
 
     public static int getNumQuickTiles(Context context) {
-        return Dependency.get(TunerService.class).getValue(NUM_QUICK_TILES, mDefaultMaxTiles);
+        // TODO(b/140052679)
+        return whitelistIpcs(() ->
+                Dependency.get(TunerService.class).getValue(NUM_QUICK_TILES, mDefaultMaxTiles));
     }
 
     void setDisabledByPolicy(boolean disabled) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index bba64d9..9178fda 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar;
 
+import static com.android.systemui.DejankUtils.whitelistIpcs;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.app.admin.DevicePolicyManager;
@@ -234,7 +236,8 @@
             return;
         }
 
-        if (!mDozing && mDevicePolicyManager.isDeviceManaged()) {
+        // TODO(b/140053632)
+        if (!mDozing && whitelistIpcs(mDevicePolicyManager::isDeviceManaged)) {
             final CharSequence organizationName =
                     mDevicePolicyManager.getDeviceOwnerOrganizationName();
             if (organizationName != null) {
@@ -381,7 +384,7 @@
             int userId = KeyguardUpdateMonitor.getCurrentUser();
             String trustGrantedIndication = getTrustGrantedIndication();
             String trustManagedIndication = getTrustManagedIndication();
-            if (!mUserManager.isUserUnlocked(userId)) {
+            if (!mKeyguardUpdateMonitor.isUserUnlocked(userId)) {
                 mTextView.switchIndication(com.android.internal.R.string.lockscreen_storage_locked);
                 mTextView.setTextColor(mInitialTextColorState);
             } else if (!TextUtils.isEmpty(mTransientIndication)) {
@@ -753,6 +756,13 @@
         }
 
         @Override
+        public void onUserSwitchComplete(int userId) {
+            if (mVisible) {
+                updateIndication(false);
+            }
+        }
+
+        @Override
         public void onUserUnlocked() {
             if (mVisible) {
                 updateIndication(false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 802a7d29..107b24c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -17,6 +17,8 @@
 
 import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED;
 
+import static com.android.systemui.DejankUtils.whitelistIpcs;
+
 import android.app.ActivityManager;
 import android.app.KeyguardManager;
 import android.app.Notification;
@@ -323,8 +325,9 @@
     }
 
     private boolean hideSilentNotificationsOnLockscreen() {
-        return Settings.Secure.getInt(mContext.getContentResolver(),
-                Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1) == 0;
+        // TODO(b/140058091)
+        return whitelistIpcs(() -> Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1) == 0);
     }
 
     private void setShowLockscreenNotifications(boolean show) {
@@ -515,8 +518,9 @@
         for (int i = currentProfiles.size() - 1; i >= 0; i--) {
             final int userId = currentProfiles.valueAt(i).id;
             boolean isProfilePublic = devicePublic;
-            boolean needsSeparateChallenge = mLockPatternUtils.isSeparateProfileChallengeEnabled(
-                    userId);
+            // TODO(b/140058091)
+            boolean needsSeparateChallenge = whitelistIpcs(() ->
+                    mLockPatternUtils.isSeparateProfileChallengeEnabled(userId));
             if (!devicePublic && userId != getCurrentUserId()
                     && needsSeparateChallenge && isSecure(userId)) {
                 // Keyguard.isDeviceLocked is updated asynchronously, assume that all profiles
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index f0eeb04..4422a81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -24,6 +24,7 @@
 import android.view.animation.Interpolator;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.systemui.DejankUtils;
 import com.android.systemui.Dumpable;
 import com.android.systemui.Interpolators;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
@@ -137,6 +138,8 @@
         recordHistoricalState(state, mState);
 
         synchronized (mListeners) {
+            String tag = getClass().getSimpleName() + "#setState(" + state + ")";
+            DejankUtils.startDetectingBlockingIpcs(tag);
             for (RankedListener rl : new ArrayList<>(mListeners)) {
                 rl.mListener.onStatePreChange(mState, state);
             }
@@ -149,6 +152,7 @@
             for (RankedListener rl : new ArrayList<>(mListeners)) {
                 rl.mListener.onStatePostChange();
             }
+            DejankUtils.stopDetectingBlockingIpcs(tag);
         }
 
         return true;
@@ -178,9 +182,12 @@
         mIsDozing = isDozing;
 
         synchronized (mListeners) {
+            String tag = getClass().getSimpleName() + "#setIsDozing";
+            DejankUtils.startDetectingBlockingIpcs(tag);
             for (RankedListener rl : new ArrayList<>(mListeners)) {
                 rl.mListener.onDozingChanged(isDozing);
             }
+            DejankUtils.stopDetectingBlockingIpcs(tag);
         }
 
         return true;
@@ -220,9 +227,12 @@
         mDozeAmount = dozeAmount;
         float interpolatedAmount = mDozeInterpolator.getInterpolation(dozeAmount);
         synchronized (mListeners) {
+            String tag = getClass().getSimpleName() + "#setDozeAmount";
+            DejankUtils.startDetectingBlockingIpcs(tag);
             for (RankedListener rl : new ArrayList<>(mListeners)) {
                 rl.mListener.onDozeAmountChanged(mDozeAmount, interpolatedAmount);
             }
+            DejankUtils.stopDetectingBlockingIpcs(tag);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index f8fef7d..0032174 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -499,10 +499,10 @@
         if (rankingMap == null) {
             return;
         }
-        NotificationListenerService.Ranking tmpRanking = new NotificationListenerService.Ranking();
+        NotificationListenerService.Ranking ranking = new NotificationListenerService.Ranking();
         for (NotificationEntry pendingNotification : mPendingNotifications.values()) {
-            rankingMap.getRanking(pendingNotification.key, tmpRanking);
-            pendingNotification.populateFromRanking(tmpRanking);
+            rankingMap.getRanking(pendingNotification.key, ranking);
+            pendingNotification.setRanking(ranking);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
index 0009292..727e245 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
@@ -213,7 +213,7 @@
             StatusBarNotification notification) {
         updateRanking(ranking);
         final StatusBarNotification oldNotification = entry.notification;
-        entry.notification = notification;
+        entry.setNotification(notification);
         mGroupManager.onEntryUpdated(entry, oldNotification);
     }
 
@@ -325,14 +325,6 @@
         return NotificationManager.IMPORTANCE_UNSPECIFIED;
     }
 
-    public String getOverrideGroupKey(String key) {
-        if (mRankingMap != null) {
-            getRanking(key, mTmpRanking);
-            return mTmpRanking.getOverrideGroupKey();
-        }
-        return null;
-    }
-
     public List<SnoozeCriterion> getSnoozeCriteria(String key) {
         if (mRankingMap != null) {
             getRanking(key, mTmpRanking);
@@ -365,23 +357,25 @@
         return false;
     }
 
-    private void updateRankingAndSort(RankingMap ranking) {
-        if (ranking != null) {
-            mRankingMap = ranking;
+    private void updateRankingAndSort(RankingMap rankingMap) {
+        if (rankingMap != null) {
+            mRankingMap = rankingMap;
             synchronized (mEntries) {
                 final int len = mEntries.size();
                 for (int i = 0; i < len; i++) {
                     NotificationEntry entry = mEntries.valueAt(i);
-                    if (!getRanking(entry.key, mTmpRanking)) {
+                    Ranking newRanking = new Ranking();
+                    if (!getRanking(entry.key, newRanking)) {
                         continue;
                     }
+                    entry.setRanking(newRanking);
+
                     final StatusBarNotification oldSbn = entry.notification.cloneLight();
-                    final String overrideGroupKey = getOverrideGroupKey(entry.key);
+                    final String overrideGroupKey = newRanking.getOverrideGroupKey();
                     if (!Objects.equals(oldSbn.getOverrideGroupKey(), overrideGroupKey)) {
                         entry.notification.setOverrideGroupKey(overrideGroupKey);
                         mGroupManager.onEntryUpdated(entry, oldSbn);
                     }
-                    entry.populateFromRanking(mTmpRanking);
                     entry.setIsHighPriority(isHighPriority(entry.notification));
                 }
             }
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 fe88541..6178488 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
@@ -38,7 +38,7 @@
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.os.SystemClock;
-import android.service.notification.NotificationListenerService;
+import android.service.notification.NotificationListenerService.Ranking;
 import android.service.notification.SnoozeCriterion;
 import android.service.notification.StatusBarNotification;
 import android.text.TextUtils;
@@ -88,6 +88,8 @@
     private static final int COLOR_INVALID = 1;
     public final String key;
     public StatusBarNotification notification;
+    private Ranking mRanking;
+
     public NotificationChannel channel;
     public long lastAudiblyAlertedMs;
     public boolean noisy;
@@ -103,7 +105,7 @@
     private long lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET;
     public CharSequence remoteInputText;
     public List<SnoozeCriterion> snoozeCriteria;
-    public int userSentiment = NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
+    public int userSentiment = Ranking.USER_SENTIMENT_NEUTRAL;
     /** Smart Actions provided by the NotificationAssistantService. */
     @NonNull
     public List<Notification.Action> systemGeneratedSmartActions = Collections.emptyList();
@@ -181,21 +183,80 @@
     private boolean mAutoHeadsUp;
     private boolean mPulseSupressed;
 
-    public NotificationEntry(StatusBarNotification n) {
-        this(n, null);
+    public NotificationEntry(
+            StatusBarNotification sbn,
+            @NonNull Ranking ranking) {
+        this(sbn, ranking, false);
     }
 
-    public NotificationEntry(
-            StatusBarNotification n,
-            @Nullable NotificationListenerService.Ranking ranking) {
-        this.key = n.getKey();
-        this.notification = n;
+    private NotificationEntry(
+            StatusBarNotification sbn,
+            Ranking ranking,
+            boolean isTest) {
+        this.key = sbn.getKey();
+        this.notification = sbn;
+
+        // TODO: Update tests to no longer need to pass null ranking
         if (ranking != null) {
-            populateFromRanking(ranking);
+            setRanking(ranking);
+        } else if (!isTest) {
+            throw new IllegalArgumentException("Ranking cannot be null");
         }
     }
 
-    public void populateFromRanking(@NonNull NotificationListenerService.Ranking ranking) {
+    /**
+     * Method for old tests that build NotificationEntries with a ranking.
+     *
+     * @deprecated New tests should pass a ranking object as well.
+     */
+    @VisibleForTesting
+    @Deprecated
+    public static NotificationEntry buildForTest(StatusBarNotification sbn) {
+        // TODO START here this will NPE on all tests
+        return new NotificationEntry(sbn, null, true);
+    }
+
+    /** The key for this notification. Guaranteed to be immutable and unique */
+    public String key() {
+        return key;
+    }
+
+    /**
+     * The StatusBarNotification that represents one half of a NotificationEntry (the other half
+     * being the Ranking). This object is swapped out whenever a notification is updated.
+     */
+    public StatusBarNotification sbn() {
+        return notification;
+    }
+
+    /**
+     * Should only be called by NotificationEntryManager and friends.
+     * TODO: Make this package-private
+     */
+    public void setNotification(StatusBarNotification sbn) {
+        if (!sbn.getKey().equals(key)) {
+            throw new IllegalArgumentException("New key " + sbn.getKey()
+                    + " doesn't match existing key " + key);
+        }
+        notification = sbn;
+    }
+
+    /**
+     * The Ranking that represents one half of a NotificationEntry (the other half being the
+     * StatusBarNotification). This object is swapped out whenever a the ranking is updated (which
+     * generally occurs whenever anything changes in the notification list).
+     */
+    public Ranking ranking() {
+        return mRanking;
+    }
+
+    /**
+     * Should only be called by NotificationEntryManager and friends.
+     * TODO: Make this package-private
+     */
+    public void setRanking(@NonNull Ranking ranking) {
+        mRanking = ranking;
+
         channel = ranking.getChannel();
         lastAudiblyAlertedMs = ranking.getLastAudiblyAlertedMillis();
         importance = ranking.getImportance();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 80d36a1..ab9162a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -76,7 +76,6 @@
 import com.android.systemui.plugins.IntentButtonProvider.IntentButton;
 import com.android.systemui.plugins.IntentButtonProvider.IntentButton.IconState;
 import com.android.systemui.statusbar.KeyguardAffordanceView;
-import com.android.systemui.statusbar.KeyguardIndicationController;
 import com.android.systemui.statusbar.policy.AccessibilityController;
 import com.android.systemui.statusbar.policy.ExtensionController;
 import com.android.systemui.statusbar.policy.ExtensionController.Extension;
@@ -117,6 +116,7 @@
     private static final int DOZE_ANIMATION_STAGGER_DELAY = 48;
     private static final int DOZE_ANIMATION_ELEMENT_DURATION = 250;
 
+    private final UnlockMethodCache mUnlockMethodCache;
     private KeyguardAffordanceView mRightAffordanceView;
     private KeyguardAffordanceView mLeftAffordanceView;
     private ViewGroup mIndicationArea;
@@ -129,7 +129,6 @@
     private View mCameraPreview;
 
     private ActivityStarter mActivityStarter;
-    private UnlockMethodCache mUnlockMethodCache;
     private LockPatternUtils mLockPatternUtils;
     private FlashlightController mFlashlightController;
     private PreviewInflater mPreviewInflater;
@@ -185,6 +184,7 @@
     public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr,
             int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
+        mUnlockMethodCache = UnlockMethodCache.getInstance(getContext());
     }
 
     private AccessibilityDelegate mAccessibilityDelegate = new AccessibilityDelegate() {
@@ -242,8 +242,6 @@
         mBurnInYOffset = getResources().getDimensionPixelSize(
                 R.dimen.default_burn_in_prevention_offset);
         updateCameraVisibility();
-        mUnlockMethodCache = UnlockMethodCache.getInstance(getContext());
-        mUnlockMethodCache.addListener(this);
         setClipChildren(false);
         setClipToPadding(false);
         inflateCameraPreview();
@@ -281,11 +279,13 @@
         getContext().registerReceiverAsUser(mDevicePolicyReceiver,
                 UserHandle.ALL, filter, null, null);
         KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallback);
+        mUnlockMethodCache.addListener(this);
     }
 
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
+        mUnlockMethodCache.removeListener(this);
         mAccessibilityController.removeStateChangedCallback(this);
         mRightExtension.destroy();
         mLeftExtension.destroy();
@@ -804,11 +804,11 @@
 
         @Override
         public IconState getIcon() {
-            ResolveInfo resolved = resolveCameraIntent();
             boolean isCameraDisabled = (mStatusBar != null) && !mStatusBar.isCameraAllowedByAdmin();
-            mIconState.isVisible = !isCameraDisabled && resolved != null
+            mIconState.isVisible = !isCameraDisabled
                     && getResources().getBoolean(R.bool.config_keyguardShowCameraAffordance)
-                    && mUserSetupComplete;
+                    && mUserSetupComplete
+                    && resolveCameraIntent() != null;
             mIconState.drawable = mContext.getDrawable(R.drawable.ic_camera_alt_24dp);
             mIconState.contentDescription =
                     mContext.getString(R.string.accessibility_camera_button);
@@ -820,7 +820,7 @@
             KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
             boolean canSkipBouncer = updateMonitor.getUserCanSkipBouncer(
                     KeyguardUpdateMonitor.getCurrentUser());
-            boolean secure = mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser());
+            boolean secure = mUnlockMethodCache.isMethodSecure();
             return (secure && !canSkipBouncer) ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index dc9b373..2e7ba045c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.phone;
 
 import static com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import static com.android.systemui.DejankUtils.whitelistIpcs;
 import static com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 
 import android.content.Context;
@@ -468,12 +469,15 @@
      * notifications on Keyguard, like SIM PIN/PUK.
      */
     public boolean needsFullscreenBouncer() {
-        ensureView();
-        if (mKeyguardView != null) {
-            SecurityMode mode = mKeyguardView.getSecurityMode();
-            return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk;
-        }
-        return false;
+        // TODO(b/140059518)
+        return whitelistIpcs(() -> {
+            ensureView();
+            if (mKeyguardView != null) {
+                SecurityMode mode = mKeyguardView.getSecurityMode();
+                return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk;
+            }
+            return false;
+        });
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
index 1d4d0bd..dcc3107 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static com.android.systemui.DejankUtils.whitelistIpcs;
+
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.os.UserManager;
@@ -98,25 +100,30 @@
         // Short-circuiting from UserManager. Needs to be extracted because of SystemUI boolean flag
         // qs_show_user_switcher_for_single_user
 
-        // The default in UserManager is to show the switcher. We want to not show it unless the
-        // user explicitly requests it in Settings
-        final boolean userSwitcherEnabled = Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.USER_SWITCHER_ENABLED, 0) != 0;
-
         // TODO(b/138661450) Move IPC calls to background
-        if (!userSwitcherEnabled
-                || !UserManager.supportsMultipleUsers()
-                || UserManager.isDeviceInDemoMode(mContext)
-                || mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)) {
-            return false;
-        }
+        return whitelistIpcs(() -> {
+            // The default in UserManager is to show the switcher. We want to not show it unless the
+            // user explicitly requests it in Settings
+            final boolean userSwitcherEnabled = Settings.Global.getInt(
+                    mContext.getContentResolver(),
+                    Settings.Global.USER_SWITCHER_ENABLED, 0) != 0;
 
-        final boolean guestEnabled = !mContext.getSystemService(DevicePolicyManager.class)
-                .getGuestUserDisabled(null);
-        return mUserSwitcherController.getSwitchableUserCount() > 1
-                // If we cannot add guests even if they are enabled, do not show
-                || (guestEnabled && !mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER))
-                || mContext.getResources().getBoolean(R.bool.qs_show_user_switcher_for_single_user);
+            if (!userSwitcherEnabled
+                    || !UserManager.supportsMultipleUsers()
+                    || UserManager.isDeviceInDemoMode(mContext)
+                    || mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)) {
+                return false;
+            }
+
+            final boolean guestEnabled = !mContext.getSystemService(DevicePolicyManager.class)
+                    .getGuestUserDisabled(null);
+            return mUserSwitcherController.getSwitchableUserCount() > 1
+                    // If we cannot add guests even if they are enabled, do not show
+                    || (guestEnabled && !mUserManager.hasUserRestriction(
+                    UserManager.DISALLOW_ADD_USER))
+                    || mContext.getResources().getBoolean(
+                    R.bool.qs_show_user_switcher_for_single_user);
+        });
     }
 
     private void registerListener() {
@@ -167,7 +174,8 @@
 
     private void refreshContentDescription() {
         String currentUser = null;
-        if (mUserManager.isUserSwitcherEnabled()
+        // TODO(b/138661450)
+        if (whitelistIpcs(mUserManager::isUserSwitcherEnabled)
                 && mUserSwitcherController != null) {
             currentUser = mUserSwitcherController.getCurrentUserName(mContext);
         }
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 c76cdcb..248bc75 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -666,6 +666,7 @@
 
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        DejankUtils.startDetectingBlockingIpcs("NVP#onLayout");
         super.onLayout(changed, left, top, right, bottom);
         setIsFullWidth(mNotificationStackScroller.getWidth() == getWidth());
 
@@ -712,6 +713,7 @@
             mExpandAfterLayoutRunnable.run();
             mExpandAfterLayoutRunnable = null;
         }
+        DejankUtils.stopDetectingBlockingIpcs("NVP#onLayout");
     }
 
     private void updateGestureExclusionRect() {
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 4c5b464..9fc3e47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -25,6 +25,7 @@
 import static android.app.StatusBarManager.windowStateToString;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
 
+import static com.android.systemui.DejankUtils.whitelistIpcs;
 import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
 import static com.android.systemui.Dependency.BG_HANDLER;
 import static com.android.systemui.Dependency.MAIN_HANDLER;
@@ -131,6 +132,7 @@
 import com.android.systemui.ActivityIntentHelper;
 import com.android.systemui.ActivityStarterDelegate;
 import com.android.systemui.AutoReinflateContainer;
+import com.android.systemui.DejankUtils;
 import com.android.systemui.DemoMode;
 import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
@@ -3680,16 +3682,21 @@
 
         @Override
         public void onStartedGoingToSleep() {
+            String tag = "StatusBar#onStartedGoingToSleep";
+            DejankUtils.startDetectingBlockingIpcs(tag);
             updateNotificationPanelTouchState();
             notifyHeadsUpGoingToSleep();
             dismissVolumeDialog();
             mWakeUpCoordinator.setFullyAwake(false);
             mBypassHeadsUpNotifier.setFullyAwake(false);
             mKeyguardBypassController.onStartedGoingToSleep();
+            DejankUtils.stopDetectingBlockingIpcs(tag);
         }
 
         @Override
         public void onStartedWakingUp() {
+            String tag = "StatusBar#onStartedWakingUp";
+            DejankUtils.startDetectingBlockingIpcs(tag);
             mDeviceInteractive = true;
             mWakeUpCoordinator.setWakingUp(true);
             if (!mKeyguardBypassController.getBypassEnabled()) {
@@ -3704,6 +3711,7 @@
             // once we fully woke up.
             updateNotificationPanelTouchState();
             mPulseExpansionHandler.onStartedWakingUp();
+            DejankUtils.stopDetectingBlockingIpcs(tag);
         }
 
         @Override
@@ -3854,18 +3862,20 @@
     }
 
     boolean isCameraAllowedByAdmin() {
-        if (mDevicePolicyManager.getCameraDisabled(null,
-                mLockscreenUserManager.getCurrentUserId())) {
-            return false;
-        } else if (mStatusBarKeyguardViewManager == null ||
-                (isKeyguardShowing() && isKeyguardSecure())) {
-            // Check if the admin has disabled the camera specifically for the keyguard
-            return (mDevicePolicyManager.
-                    getKeyguardDisabledFeatures(null, mLockscreenUserManager.getCurrentUserId())
-                    & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) == 0;
-        }
-
-        return true;
+        // TODO(b/140060745)
+        return whitelistIpcs(() -> {
+            if (mDevicePolicyManager.getCameraDisabled(null,
+                    mLockscreenUserManager.getCurrentUserId())) {
+                return false;
+            } else if (mStatusBarKeyguardViewManager == null
+                    || (isKeyguardShowing() && isKeyguardSecure())) {
+                // Check if the admin has disabled the camera specifically for the keyguard
+                return (mDevicePolicyManager.getKeyguardDisabledFeatures(null,
+                        mLockscreenUserManager.getCurrentUserId())
+                        & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) == 0;
+            }
+            return true;
+        });
     }
 
     private boolean isGoingToSleep() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
index 0ef981b..e85b147 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
@@ -18,6 +18,7 @@
 
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 
+import static com.android.systemui.DejankUtils.whitelistIpcs;
 import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
 
 import android.app.ActivityManager;
@@ -370,12 +371,14 @@
             mWindowManager.updateViewLayout(mStatusBarView, mLp);
         }
         if (mHasTopUi != mHasTopUiChanged) {
-            try {
-                mActivityManager.setHasTopUi(mHasTopUiChanged);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Failed to call setHasTopUi", e);
-            }
-            mHasTopUi = mHasTopUiChanged;
+            whitelistIpcs(() -> {
+                try {
+                    mActivityManager.setHasTopUi(mHasTopUiChanged);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Failed to call setHasTopUi", e);
+                }
+                mHasTopUi = mHasTopUiChanged;
+            });
         }
         notifyStateChangedCallbacks();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 6789930..7a81ed4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -65,8 +65,6 @@
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.DragDownHelper;
-import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.phone.ScrimController.ScrimVisibility;
 import com.android.systemui.tuner.TunerService;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
index b1d6ca6..24ecd14 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
@@ -27,6 +27,7 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.systemui.DejankUtils;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -133,15 +134,20 @@
             mTrusted = trusted;
             mTrustManaged = trustManaged;
             mFaceAuthEnabled = faceAuthEnabled;
+            Trace.endSection();
             notifyListeners();
+        } else {
+            Trace.endSection();
         }
-        Trace.endSection();
     }
 
     private void notifyListeners() {
+        String tag = "UnlockMethodCache#notifyListeners";
+        DejankUtils.startDetectingBlockingIpcs(tag);
         for (OnUnlockMethodChangedListener listener : mListeners) {
             listener.onUnlockMethodStateChanged();
         }
+        DejankUtils.stopDetectingBlockingIpcs(tag);
     }
 
     public void dump(PrintWriter pw) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
index abe3f2c..fc6e5e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
@@ -18,12 +18,12 @@
 import static com.android.systemui.statusbar.policy.NetworkControllerImpl.TAG;
 
 import android.content.Context;
-import android.text.format.DateFormat;
 import android.util.Log;
 
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
 
 import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
 import java.util.BitSet;
 
 
@@ -254,6 +254,8 @@
     }
 
     static class State {
+        // No locale as it's only used for logging purposes
+        private static SimpleDateFormat sSDF = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
         boolean connected;
         boolean enabled;
         boolean activityIn;
@@ -301,7 +303,7 @@
                     .append("activityOut=").append(activityOut).append(',')
                     .append("activityDormant=").append(activityDormant).append(',')
                     .append("rssi=").append(rssi).append(',')
-                    .append("lastModified=").append(DateFormat.format("MM-dd HH:mm:ss", time));
+                    .append("lastModified=").append(sSDF.format(time));
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 395add7..2e1e520 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.policy;
 
 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+import static com.android.systemui.DejankUtils.whitelistIpcs;
 import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
 
 import android.app.ActivityManager;
@@ -313,9 +314,10 @@
         // adb shell settings put system enable_fullscreen_user_switcher 1  # Turn it on.
         // Restart SystemUI or adb reboot.
         final int DEFAULT = -1;
+        // TODO(b/140061064)
         final int overrideUseFullscreenUserSwitcher =
-                Settings.System.getInt(mContext.getContentResolver(),
-                        "enable_fullscreen_user_switcher", DEFAULT);
+                whitelistIpcs(() -> Settings.System.getInt(mContext.getContentResolver(),
+                        "enable_fullscreen_user_switcher", DEFAULT));
         if (overrideUseFullscreenUserSwitcher != DEFAULT) {
             return overrideUseFullscreenUserSwitcher != 0;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
index aa4dcc0..a55e2cf 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
@@ -34,6 +34,7 @@
 import android.util.ArraySet;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.systemui.DejankUtils;
 import com.android.systemui.DemoMode;
 import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.settings.CurrentUserTracker;
@@ -189,7 +190,8 @@
             mContentResolver.registerContentObserver(uri, false, mObserver, mCurrentUser);
         }
         // Send the first state.
-        String value = Settings.Secure.getStringForUser(mContentResolver, key, mCurrentUser);
+        String value = DejankUtils.whitelistIpcs(() -> Settings.Secure
+                .getStringForUser(mContentResolver, key, mCurrentUser));
         tunable.onTuningChanged(key, value);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/util/DeviceConfigProxy.java b/packages/SystemUI/src/com/android/systemui/util/DeviceConfigProxy.java
new file mode 100644
index 0000000..3a2172a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/DeviceConfigProxy.java
@@ -0,0 +1,131 @@
+/*
+ * 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;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.provider.DeviceConfig;
+import android.provider.Settings;
+
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+
+/**
+ * Wrapper around DeviceConfig useful for testing.
+ */
+public class DeviceConfigProxy {
+    @Inject
+    public DeviceConfigProxy() {
+    }
+
+    /**
+     * Wrapped version of {@link DeviceConfig#addOnPropertiesChangedListener}.
+     */
+    public void addOnPropertiesChangedListener(
+            @NonNull String namespace,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull DeviceConfig.OnPropertiesChangedListener onPropertiesChangedListener) {
+        DeviceConfig.addOnPropertiesChangedListener(
+                namespace, executor, onPropertiesChangedListener);
+    }
+
+    /**
+     * Wrapped version of {@link DeviceConfig#enforceReadPermission}.
+     */
+    public void enforceReadPermission(Context context, String namespace) {
+        DeviceConfig.enforceReadPermission(context, namespace);
+    }
+
+    /**
+     * Wrapped version of {@link DeviceConfig#getBoolean}.
+     */
+    public boolean getBoolean(
+            @NonNull String namespace, @NonNull String name, boolean defaultValue) {
+        return DeviceConfig.getBoolean(namespace, name, defaultValue);
+    }
+
+    /**
+     * Wrapped version of {@link DeviceConfig#getFloat}.
+     */
+    public float getFloat(
+            @NonNull String namespace, @NonNull String name, float defaultValue) {
+        return DeviceConfig.getFloat(namespace, name, defaultValue);
+    }
+
+    /**
+     * Wrapped version of {@link DeviceConfig#getInt}.
+     */
+    public int getInt(@NonNull String namespace, @NonNull String name, int defaultValue) {
+        return DeviceConfig.getInt(namespace, name, defaultValue);
+    }
+
+    /**
+     * Wrapped version of {@link DeviceConfig#getLong}.
+     */
+    public long getLong(@NonNull String namespace, @NonNull String name, long defaultValue) {
+        return DeviceConfig.getLong(namespace, name, defaultValue);
+
+    }
+
+    /**
+     * Wrapped version of {@link DeviceConfig#getProperty}.
+     */
+    public String getProperty(@NonNull String namespace, @NonNull String name) {
+        return DeviceConfig.getProperty(namespace, name);
+    }
+
+    /**
+     * Wrapped version of {@link DeviceConfig#getString}.
+     */
+    public String getString(
+            @NonNull String namespace, @NonNull String name, @Nullable String defaultValue) {
+        return DeviceConfig.getString(namespace, name, defaultValue);
+    }
+
+    /**
+     * Wrapped version of {@link DeviceConfig#removeOnPropertiesChangedListener}.
+     *
+     * Like {@link #addOnPropertiesChangedListener}, this operates on a callback type that
+     * wraps the original callback type provided by {@link DeviceConfig}.
+     */
+    public void removeOnPropertiesChangedListener(
+            @NonNull DeviceConfig.OnPropertiesChangedListener onPropertiesChangedListener) {
+        DeviceConfig.removeOnPropertiesChangedListener(onPropertiesChangedListener);
+    }
+
+    /**
+     * Wrapped version of {@link DeviceConfig#resetToDefaults}.
+     */
+    public void resetToDefaults(@Settings.ResetMode int resetMode,
+            @Nullable String namespace) {
+        DeviceConfig.resetToDefaults(resetMode, namespace);
+    }
+
+    /**
+     * Wrapped version of {@link DeviceConfig#setProperty}.
+     */
+    public boolean setProperty(
+            @NonNull String namespace,
+            @NonNull String name,
+            @Nullable String value,
+            boolean makeDefault) {
+        return DeviceConfig.setProperty(namespace, name, value, makeDefault);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index a3cb6c0..fce79c3 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -477,6 +477,16 @@
         assertThat(listToVerify.get(0)).isEqualTo(TEST_SUBSCRIPTION_2);
     }
 
+    @Test
+    public void testIsUserUnlocked() {
+        // mUserManager will report the user as unlocked on @Before
+        assertThat(mKeyguardUpdateMonitor.isUserUnlocked(KeyguardUpdateMonitor.getCurrentUser()))
+                .isTrue();
+        // Invalid user should not be unlocked.
+        int randomUser = 99;
+        assertThat(mKeyguardUpdateMonitor.isUserUnlocked(randomUser)).isFalse();
+    }
+
     private Intent putPhoneInfo(Intent intent, Bundle data, Boolean simInited) {
         int subscription = simInited
                 ? 1/* mock subid=1 */ : SubscriptionManager.DUMMY_SUBSCRIPTION_ID_BASE;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
index 8a6ee12..ccd2138 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
@@ -392,18 +392,18 @@
     }
 
     private void entryRemoved(StatusBarNotification notification) {
-        mEntryListener.onEntryRemoved(new NotificationEntry(notification),
+        mEntryListener.onEntryRemoved(NotificationEntry.buildForTest(notification),
                 null, false);
     }
 
     private void entryAdded(StatusBarNotification notification, int importance) {
-        NotificationEntry entry = new NotificationEntry(notification);
+        NotificationEntry entry = NotificationEntry.buildForTest(notification);
         entry.importance = importance;
         mEntryListener.onPendingEntryAdded(entry);
     }
 
     private void entryUpdated(StatusBarNotification notification, int importance) {
-        NotificationEntry entry = new NotificationEntry(notification);
+        NotificationEntry entry = NotificationEntry.buildForTest(notification);
         entry.importance = importance;
         mEntryListener.onPostEntryUpdated(entry);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiBaseFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiBaseFragmentTest.java
index 256cfb2..a245d41 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiBaseFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiBaseFragmentTest.java
@@ -42,7 +42,7 @@
     public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
             new DexmakerShareClassLoaderRule();
 
-    protected final TestableDependency mDependency = new TestableDependency(mContext);
+    protected TestableDependency mDependency;
     protected SysuiTestableContext mSysuiContext;
     private Instrumentation mRealInstrumentation;
 
@@ -53,6 +53,7 @@
     @Before
     public void SysuiSetup() {
         SystemUIFactory.createFromConfig(mContext);
+        mDependency = new TestableDependency(mContext);
         // TODO: Figure out another way to give reference to a SysuiTestableContext.
         mSysuiContext = (SysuiTestableContext) mContext;
 
@@ -69,6 +70,7 @@
     public void SysuiTeardown() {
         InstrumentationRegistry.registerInstance(mRealInstrumentation,
                 InstrumentationRegistry.getArguments());
+        SystemUIFactory.cleanup();
     }
 
     @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index 8d93f96..e4f33e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -55,12 +55,13 @@
     @Rule
     public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
             new DexmakerShareClassLoaderRule();
-    public TestableDependency mDependency = new TestableDependency(mContext);
+    public TestableDependency mDependency;
     private Instrumentation mRealInstrumentation;
 
     @Before
     public void SysuiSetup() throws Exception {
         SystemUIFactory.createFromConfig(mContext);
+        mDependency = new TestableDependency(mContext);
 
         mRealInstrumentation = InstrumentationRegistry.getInstrumentation();
         Instrumentation inst = spy(mRealInstrumentation);
@@ -82,6 +83,7 @@
                 InstrumentationRegistry.getArguments());
         // Reset the assert's main looper.
         Assert.sMainLooper = Looper.getMainLooper();
+        SystemUIFactory.cleanup();
     }
 
     protected LeakCheck getLeakCheck() {
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 815a70a..3eea853 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
@@ -878,7 +878,7 @@
         when(sbn.getNotification()).thenReturn(notification);
 
         // NotificationEntry -> StatusBarNotification -> Notification -> BubbleMetadata
-        return new NotificationEntry(sbn);
+        return NotificationEntry.buildForTest(sbn);
     }
 
     private void setCurrentTime(long time) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java
index 7ea6493..2073ae1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java
@@ -31,6 +31,8 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.classifier.brightline.BrightLineFalsingManager;
 import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.util.DeviceConfigProxy;
+import com.android.systemui.util.DeviceConfigProxyFake;
 
 import org.junit.After;
 import org.junit.Before;
@@ -45,8 +47,9 @@
 public class FalsingManagerProxyTest extends SysuiTestCase {
     @Mock
     PluginManager mPluginManager;
-    private boolean mDefaultConfigValue;
     private Handler mHandler;
+    private FalsingManagerProxy mProxy;
+    private DeviceConfigProxy mDeviceConfig;
     private TestableLooper mTestableLooper;
 
     @Before
@@ -54,50 +57,47 @@
         MockitoAnnotations.initMocks(this);
         mTestableLooper = TestableLooper.get(this);
         mHandler = new Handler(mTestableLooper.getLooper());
-        mDefaultConfigValue = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
-                BRIGHTLINE_FALSING_MANAGER_ENABLED, false);
-        // In case it runs on a device where it's been set to true, set it to false by hand.
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
+        mDeviceConfig = new DeviceConfigProxyFake();
+        mDeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
                 BRIGHTLINE_FALSING_MANAGER_ENABLED, "false", false);
     }
 
     @After
     public void tearDown() {
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
-                BRIGHTLINE_FALSING_MANAGER_ENABLED, mDefaultConfigValue ? "true" : "false", false);
+        if (mProxy != null) {
+            mProxy.cleanup();
+        }
     }
 
     @Test
     public void test_brightLineFalsingManagerDisabled() {
-        FalsingManagerProxy proxy = new FalsingManagerProxy(getContext(), mPluginManager, mHandler);
-
-        assertThat(proxy.getInternalFalsingManager(), instanceOf(FalsingManagerImpl.class));
+        mProxy = new FalsingManagerProxy(getContext(), mPluginManager, mHandler, mDeviceConfig);
+        assertThat(mProxy.getInternalFalsingManager(), instanceOf(FalsingManagerImpl.class));
     }
 
     @Test
-    public void test_brightLineFalsingManagerEnabled() {
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
-                BRIGHTLINE_FALSING_MANAGER_ENABLED, "true", false);
-        FalsingManagerProxy proxy = new FalsingManagerProxy(getContext(), mPluginManager, mHandler);
-
-        assertThat(proxy.getInternalFalsingManager(), instanceOf(BrightLineFalsingManager.class));
-    }
-
-    @Test
-    public void test_brightLineFalsingManagerToggled() {
-        FalsingManagerProxy proxy = new FalsingManagerProxy(getContext(), mPluginManager, mHandler);
-        assertThat(proxy.getInternalFalsingManager(), instanceOf(FalsingManagerImpl.class));
-
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
+    public void test_brightLineFalsingManagerEnabled() throws InterruptedException {
+        mDeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
                 BRIGHTLINE_FALSING_MANAGER_ENABLED, "true", false);
         mTestableLooper.processAllMessages();
-        proxy.setupFalsingManager(getContext());
-        assertThat(proxy.getInternalFalsingManager(), instanceOf(BrightLineFalsingManager.class));
+        mProxy = new FalsingManagerProxy(getContext(), mPluginManager, mHandler, mDeviceConfig);
+        assertThat(mProxy.getInternalFalsingManager(), instanceOf(BrightLineFalsingManager.class));
+    }
 
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
+    @Test
+    public void test_brightLineFalsingManagerToggled() throws InterruptedException {
+        mProxy = new FalsingManagerProxy(getContext(), mPluginManager, mHandler, mDeviceConfig);
+        assertThat(mProxy.getInternalFalsingManager(), instanceOf(FalsingManagerImpl.class));
+
+        mDeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
+                BRIGHTLINE_FALSING_MANAGER_ENABLED, "true", false);
+        mTestableLooper.processAllMessages();
+        assertThat(mProxy.getInternalFalsingManager(),
+                instanceOf(BrightLineFalsingManager.class));
+
+        mDeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
                 BRIGHTLINE_FALSING_MANAGER_ENABLED, "false", false);
         mTestableLooper.processAllMessages();
-        proxy.setupFalsingManager(getContext());
-        assertThat(proxy.getInternalFalsingManager(), instanceOf(FalsingManagerImpl.class));
+        assertThat(mProxy.getInternalFalsingManager(), instanceOf(FalsingManagerImpl.class));
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java
index b45d3f2..afe4200 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java
@@ -28,6 +28,8 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.systemui.util.DeviceConfigProxyFake;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -58,7 +60,7 @@
     public void setup() {
         super.setup();
         MockitoAnnotations.initMocks(this);
-        mClassifier = new DiagonalClassifier(mDataProvider);
+        mClassifier = new DiagonalClassifier(mDataProvider, new DeviceConfigProxyFake());
     }
 
     @After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java
index 805bb91..f0f5fc7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java
@@ -24,6 +24,8 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.systemui.util.DeviceConfigProxyFake;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -41,7 +43,7 @@
     public void setup() {
         super.setup();
         mDataProvider = getDataProvider();
-        mClassifier = new DistanceClassifier(mDataProvider);
+        mClassifier = new DistanceClassifier(mDataProvider, new DeviceConfigProxyFake());
     }
 
     @After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java
index a6cabbf..c76fe74 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java
@@ -31,6 +31,8 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.systemui.util.DeviceConfigProxyFake;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -60,7 +62,8 @@
         MockitoAnnotations.initMocks(this);
         when(mDataProvider.getInteractionType()).thenReturn(GENERIC);
         when(mDistanceClassifier.isLongSwipe()).thenReturn(false);
-        mClassifier = new ProximityClassifier(mDistanceClassifier, mDataProvider);
+        mClassifier = new ProximityClassifier(
+                mDistanceClassifier, mDataProvider, new DeviceConfigProxyFake());
     }
 
     @After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java
index fb4c1ec..387c0da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java
@@ -24,6 +24,8 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.systemui.util.DeviceConfigProxyFake;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -41,7 +43,7 @@
     @Before
     public void setup() {
         super.setup();
-        mClassifier = new ZigZagClassifier(getDataProvider());
+        mClassifier = new ZigZagClassifier(getDataProvider(), new DeviceConfigProxyFake());
     }
 
     @After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/DismissCallbackRegistryTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/DismissCallbackRegistryTest.java
index d35fc30..7fa1dbe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/DismissCallbackRegistryTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/DismissCallbackRegistryTest.java
@@ -38,12 +38,13 @@
 @RunWith(AndroidJUnit4.class)
 public class DismissCallbackRegistryTest extends SysuiTestCase {
 
-    private final DismissCallbackRegistry mDismissCallbackRegistry = new DismissCallbackRegistry();
+    private DismissCallbackRegistry mDismissCallbackRegistry;
     private @Mock IKeyguardDismissCallback mMockCallback;
     private @Mock IKeyguardDismissCallback mMockCallback2;
 
     @Before
     public void setUp() throws Exception {
+        mDismissCallbackRegistry =  new DismissCallbackRegistry();
         MockitoAnnotations.initMocks(this);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
index 881cc39..e6f36e6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
@@ -129,7 +129,7 @@
     public void setUp() {
         mTestHandler = Handler.createAsync(Looper.myLooper());
         mSbn = createNewNotification(0 /* id */);
-        mEntry = new NotificationEntry(mSbn);
+        mEntry = NotificationEntry.buildForTest(mSbn);
         mEntry.setRow(mRow);
 
         mAlertingNotificationManager = createAlertingNotificationManager();
@@ -180,7 +180,7 @@
     public void testReleaseAllImmediately() {
         for (int i = 0; i < TEST_NUM_NOTIFICATIONS; i++) {
             StatusBarNotification sbn = createNewNotification(i);
-            NotificationEntry entry = new NotificationEntry(sbn);
+            NotificationEntry entry = NotificationEntry.buildForTest(sbn);
             entry.setRow(mRow);
             mAlertingNotificationManager.showNotification(entry);
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index daee55b..2427cfc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -268,12 +268,18 @@
     public void unlockMethodCache_listenerUpdatesIndication() {
         createController();
         String restingIndication = "Resting indication";
-        when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
-        mController.setRestingIndication(restingIndication);
+
         mController.setVisible(true);
+        assertThat(mTextView.getText()).isEqualTo(
+                mContext.getString(com.android.internal.R.string.lockscreen_storage_locked));
+
+        when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
+        when(mKeyguardUpdateMonitor.isUserUnlocked(anyInt())).thenReturn(true);
+        mController.setRestingIndication(restingIndication);
         assertThat(mTextView.getText()).isEqualTo(mController.getTrustGrantedIndication());
 
         reset(mKeyguardUpdateMonitor);
+        when(mKeyguardUpdateMonitor.isUserUnlocked(anyInt())).thenReturn(true);
         when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(false);
         mController.onUnlockMethodStateChanged();
         assertThat(mTextView.getText()).isEqualTo(restingIndication);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
index 0800cb9..55ce8d60 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
@@ -91,7 +91,7 @@
 
     @Test
     public void testNotificationUpdateCallsUpdateNotification() {
-        when(mNotificationData.get(mSbn.getKey())).thenReturn(new NotificationEntry(mSbn));
+        when(mNotificationData.get(mSbn.getKey())).thenReturn(NotificationEntry.buildForTest(mSbn));
         mListener.onNotificationPosted(mSbn, mRanking);
         TestableLooper.get(this).processAllMessages();
         verify(mEntryManager).updateNotification(mSbn, mRanking);
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 da25eed..99d09f1 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,6 @@
 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.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.ShadeController;
 
 import com.google.android.collect.Sets;
@@ -81,7 +80,7 @@
                 Handler.createAsync(Looper.myLooper()));
         mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID,
                 0, new Notification(), UserHandle.CURRENT, null, 0);
-        mEntry = new NotificationEntry(mSbn);
+        mEntry = NotificationEntry.buildForTest(mSbn);
         mEntry.setRow(mRow);
 
         mRemoteInputManager.setUpWithPresenterForTest(mCallback,
@@ -176,7 +175,7 @@
         // Setup a notification entry with 1 remote input.
         StatusBarNotification newSbn =
                 mRemoteInputManager.rebuildNotificationWithRemoteInput(mEntry, "A Reply", false);
-        NotificationEntry entry = new NotificationEntry(newSbn);
+        NotificationEntry entry = NotificationEntry.buildForTest(newSbn);
 
         // Try rebuilding to add another reply.
         newSbn = mRemoteInputManager.rebuildNotificationWithRemoteInput(entry, "Reply 2", true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
index 7063ddf..99428ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
@@ -50,7 +50,6 @@
 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 /**
  * A helper class to create {@link ExpandableNotificationRow} (for both individual and group
@@ -307,7 +306,7 @@
                 userHandle,
                 null /* overrideGroupKey */,
                 System.currentTimeMillis());
-        NotificationEntry entry = new NotificationEntry(sbn);
+        NotificationEntry entry = NotificationEntry.buildForTest(sbn);
         entry.setRow(row);
         entry.createIcons(mContext, sbn);
         entry.channel = new NotificationChannel(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index 58fb53a..54d8688 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -119,7 +119,7 @@
 
     private NotificationEntry createEntry() throws Exception {
         ExpandableNotificationRow row = mHelper.createRow();
-        NotificationEntry entry = new NotificationEntry(row.getStatusBarNotification());
+        NotificationEntry entry = NotificationEntry.buildForTest(row.getStatusBarNotification());
         entry.setRow(row);
         return entry;
     }
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 185723f..e54ea6a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
@@ -97,7 +97,7 @@
 
         mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID,
                 0, mNotification, new UserHandle(ActivityManager.getCurrentUser()), null, 0);
-        mEntry = new NotificationEntry(mSbn);
+        mEntry = NotificationEntry.buildForTest(mSbn);
     }
 
     @Test
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 2ca1b06..36b143b 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
@@ -239,7 +239,7 @@
                 .setContentText("Text");
         mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID,
                 0, n.build(), new UserHandle(ActivityManager.getCurrentUser()), null, 0);
-        mEntry = new NotificationEntry(mSbn);
+        mEntry = NotificationEntry.buildForTest(mSbn);
         mEntry.expandedIcon = mock(StatusBarIconView.class);
 
         mEntryManager = new TestableNotificationEntryManager(mContext);
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 6f7751b..b522316 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
@@ -195,12 +195,12 @@
 
         // test should filter out hidden notifications:
         // hidden
-        NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
+        NotificationEntry entry = NotificationEntry.buildForTest(mMockStatusBarNotification);
         entry.suspended = true;
         assertTrue(mNotificationFilter.shouldFilterOut(entry));
 
         // not hidden
-        entry = new NotificationEntry(mMockStatusBarNotification);
+        entry = NotificationEntry.buildForTest(mMockStatusBarNotification);
         entry.suspended = false;
         assertFalse(mNotificationFilter.shouldFilterOut(entry));
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
index 311b81c..e42d155 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
@@ -234,7 +234,7 @@
                         new UserHandle(ActivityManager.getCurrentUser()),
                         null,
                         0);
-        return new NotificationEntry(notification);
+        return NotificationEntry.buildForTest(notification);
     }
 
     private static final String TEST_PACKAGE_NAME = "test";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
index dd2630b..49229ca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
@@ -62,7 +62,7 @@
 
         mVisualStabilityManager.setUpWithPresenter(mock(NotificationPresenter.class));
         mVisualStabilityManager.setVisibilityLocationProvider(mLocationProvider);
-        mEntry = new NotificationEntry(mock(StatusBarNotification.class));
+        mEntry = NotificationEntry.buildForTest(mock(StatusBarNotification.class));
         mEntry.setRow(mRow);
 
         when(mRow.getEntry()).thenReturn(mEntry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
index e2d8e56..ed719d9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
@@ -233,7 +233,7 @@
 
         Notification n = mMockStatusBarNotification.getNotification();
         n.flags = Notification.FLAG_FOREGROUND_SERVICE;
-        NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
+        NotificationEntry entry = NotificationEntry.buildForTest(mMockStatusBarNotification);
         entry.setRow(mRow);
         mNotificationData.add(entry);
         Bundle override = new Bundle();
@@ -252,7 +252,7 @@
         nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
         n = nb.build();
         when(mMockStatusBarNotification.getNotification()).thenReturn(n);
-        NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
+        NotificationEntry entry = NotificationEntry.buildForTest(mMockStatusBarNotification);
         entry.setRow(mRow);
         mNotificationData.add(entry);
         Bundle override = new Bundle();
@@ -266,7 +266,7 @@
     @Test
     public void testIsExemptFromDndVisualSuppression_system() {
         initStatusBarNotification(false);
-        NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
+        NotificationEntry entry = NotificationEntry.buildForTest(mMockStatusBarNotification);
         entry.setRow(mRow);
         entry.mIsSystemNotification = true;
         mNotificationData.add(entry);
@@ -281,7 +281,7 @@
     @Test
     public void testIsNotExemptFromDndVisualSuppression_hiddenCategories() {
         initStatusBarNotification(false);
-        NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
+        NotificationEntry entry = NotificationEntry.buildForTest(mMockStatusBarNotification);
         entry.setRow(mRow);
         entry.mIsSystemNotification = true;
         Bundle override = new Bundle();
@@ -369,7 +369,7 @@
         StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
                 notification, mContext.getUser(), "", 0);
 
-        NotificationEntry entry = new NotificationEntry(sbn);
+        NotificationEntry entry = NotificationEntry.buildForTest(sbn);
         entry.setHasSentReply();
 
         assertTrue(entry.isLastMessageFromReply());
@@ -474,7 +474,7 @@
                 .build();
         StatusBarNotification aSbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
                 aN, mContext.getUser(), "", 0);
-        NotificationEntry a = new NotificationEntry(aSbn);
+        NotificationEntry a = NotificationEntry.buildForTest(aSbn);
         a.setRow(mock(ExpandableNotificationRow.class));
         a.setIsHighPriority(false);
 
@@ -488,7 +488,7 @@
                 .build();
         StatusBarNotification bSbn = new StatusBarNotification("pkg2", "pkg2", 0, "tag", 0, 0,
                 bN, mContext.getUser(), "", 0);
-        NotificationEntry b = new NotificationEntry(bSbn);
+        NotificationEntry b = NotificationEntry.buildForTest(bSbn);
         b.setIsHighPriority(true);
         b.setRow(mock(ExpandableNotificationRow.class));
 
@@ -509,7 +509,7 @@
                 .build();
         StatusBarNotification aSbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
                 aN, mContext.getUser(), "", 0);
-        NotificationEntry a = new NotificationEntry(aSbn);
+        NotificationEntry a = NotificationEntry.buildForTest(aSbn);
         a.setRow(mock(ExpandableNotificationRow.class));
         a.setIsHighPriority(false);
 
@@ -523,7 +523,7 @@
                 .build();
         StatusBarNotification bSbn = new StatusBarNotification("pkg2", "pkg2", 0, "tag", 0, 0,
                 bN, mContext.getUser(), "", 0);
-        NotificationEntry b = new NotificationEntry(bSbn);
+        NotificationEntry b = NotificationEntry.buildForTest(bSbn);
         b.setRow(mock(ExpandableNotificationRow.class));
         b.setIsHighPriority(false);
 
@@ -556,7 +556,7 @@
         override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_DEFAULT);
         mNotificationData.rankingOverrides.put(sbn.getKey(), override);
 
-        NotificationEntry entry = new NotificationEntry(sbn);
+        NotificationEntry entry = NotificationEntry.buildForTest(sbn);
         entry.setRow(mRow);
         mNotificationData.add(entry);
 
@@ -583,7 +583,7 @@
         override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
         mNotificationData.rankingOverrides.put(sbn.getKey(), override);
 
-        NotificationEntry entry = new NotificationEntry(sbn);
+        NotificationEntry entry = NotificationEntry.buildForTest(sbn);
         entry.setRow(mRow);
 
         mNotificationData.add(entry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
index cca9f28..57a6aae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
@@ -23,6 +23,7 @@
 
 import android.app.Notification;
 import android.os.Bundle;
+import android.service.notification.NotificationListenerService.Ranking;
 import android.service.notification.StatusBarNotification;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -59,7 +60,18 @@
         mExtras = new Bundle();
         mNotif.extras = mExtras;
 
-        mEntry = new NotificationEntry(mStatusBarNotification);
+        mEntry = NotificationEntry.buildForTest(mStatusBarNotification);
+    }
+
+    @Test
+    public void testInitialization() {
+        final Ranking ranking = new Ranking();
+
+        final NotificationEntry entry = new NotificationEntry(mStatusBarNotification, ranking);
+
+        assertEquals("key", entry.key());
+        assertEquals(mStatusBarNotification, entry.sbn());
+        assertEquals(ranking, entry.ranking());
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index 5e587f8..ff3a2e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -96,7 +96,7 @@
         StatusBarNotification sbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME,
                 0, null, TEST_UID,
                 0, new Notification(), UserHandle.CURRENT, null, 0);
-        mEntry = new NotificationEntry(sbn);
+        mEntry = NotificationEntry.buildForTest(sbn);
         mEntry.setRow(mRow);
 
         mLogger = new TestableNotificationLogger(mListener, Dependency.get(UiOffloadThread.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
index 13b9d56..98e1692 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
@@ -60,7 +60,7 @@
     public void setup() {
         injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
         mRow = mock(ExpandableNotificationRow.class);
-        NotificationEntry entry = new NotificationEntry(
+        NotificationEntry entry = NotificationEntry.buildForTest(
                 mock(StatusBarNotification.class));
         entry.channel = mock(NotificationChannel.class);
         when(mRow.getEntry()).thenReturn(entry);
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 48934da..de3623f 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
@@ -121,7 +121,7 @@
 
     @Test
     public void testCanRemoveImmediately_notTopEntry() {
-        NotificationEntry laterEntry = new NotificationEntry(createNewNotification(1));
+        NotificationEntry laterEntry = NotificationEntry.buildForTest(createNewNotification(1));
         laterEntry.setRow(mRow);
         mHeadsUpManager.showNotification(mEntry);
         mHeadsUpManager.showNotification(laterEntry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
index 75aae01..33d3ac8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
@@ -82,8 +82,7 @@
     private FragmentController mControllerExternalDisplay;
 
     private SysuiTestableContext mSysuiTestableContextExternal;
-    private OverviewProxyService mOverviewProxyService =
-            mDependency.injectMockDependency(OverviewProxyService.class);
+    private OverviewProxyService mOverviewProxyService;
     private CommandQueue mCommandQueue;
     private SysUiState mMockSysUiState;
 
@@ -115,6 +114,8 @@
     public void setupFragment() throws Exception {
         setupSysuiDependency();
         createRootView();
+        mOverviewProxyService =
+                mDependency.injectMockDependency(OverviewProxyService.class);
         TestableLooper.get(this).runWithLooper(() -> {
             mHandler = new Handler();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarRotationContextTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarRotationContextTest.java
index cf08428..d6b38ff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarRotationContextTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarRotationContextTest.java
@@ -30,7 +30,6 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.SysuiTestableContext;
-import com.android.systemui.TestableDependency;
 import com.android.systemui.statusbar.policy.KeyButtonDrawable;
 import com.android.systemui.statusbar.policy.RotationLockController;
 
@@ -50,7 +49,6 @@
     @Rule
     public final SysuiTestableContext mContext = new SysuiTestableContext(
             InstrumentationRegistry.getContext(), getLeakCheck());
-    private final TestableDependency mDependency = new TestableDependency(mContext);
     private RotationButtonController mRotationButtonController;
     private RotationButton mRotationButton;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
index b1c3c83..a0d264d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
@@ -256,7 +256,7 @@
         StatusBarNotification oldNotification = childEntry.notification;
         StatusBarNotification newSbn = spy(childEntry.notification.clone());
         doReturn("other_group").when(newSbn).getGroupKey();
-        childEntry.notification = newSbn;
+        childEntry.setNotification(newSbn);
         mGroupManager.onEntryUpdated(childEntry, oldNotification);
 
         assertFalse(mGroupAlertTransferHelper.isAlertTransferPending(childEntry));
@@ -267,7 +267,7 @@
         NotificationEntry summaryEntry =
                 mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
         NotificationEntry childEntry =
-                mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
+                mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY, 47);
         when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag()))
             .thenReturn(false);
         mHeadsUpManager.showNotification(summaryEntry);
@@ -277,8 +277,9 @@
 
         // Update that child to a summary.
         StatusBarNotification oldNotification = childEntry.notification;
-        childEntry.notification = mGroupTestHelper.createSummaryNotification(
-                Notification.GROUP_ALERT_SUMMARY).notification;
+        childEntry.setNotification(
+                mGroupTestHelper.createSummaryNotification(
+                        Notification.GROUP_ALERT_SUMMARY, 47).notification);
         mGroupManager.onEntryUpdated(childEntry, oldNotification);
 
         assertFalse(mGroupAlertTransferHelper.isAlertTransferPending(childEntry));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java
index e6b9778..e33545b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java
@@ -45,11 +45,15 @@
     }
 
     public NotificationEntry createSummaryNotification() {
-        return createSummaryNotification(Notification.GROUP_ALERT_ALL);
+        return createSummaryNotification(Notification.GROUP_ALERT_ALL, mId++);
     }
 
     public NotificationEntry createSummaryNotification(int groupAlertBehavior) {
-        return createEntry(true, groupAlertBehavior);
+        return createSummaryNotification(groupAlertBehavior, mId++);
+    }
+
+    public NotificationEntry createSummaryNotification(int groupAlertBehavior, int id) {
+        return createEntry(id, true, groupAlertBehavior);
     }
 
     public NotificationEntry createChildNotification() {
@@ -57,10 +61,14 @@
     }
 
     public NotificationEntry createChildNotification(int groupAlertBehavior) {
-        return createEntry(false, groupAlertBehavior);
+        return createEntry(mId++, false, groupAlertBehavior);
     }
 
-    public NotificationEntry createEntry(boolean isSummary, int groupAlertBehavior) {
+    public NotificationEntry createChildNotification(int groupAlertBehavior, int id) {
+        return createEntry(id, false, groupAlertBehavior);
+    }
+
+    public NotificationEntry createEntry(int id, boolean isSummary, int groupAlertBehavior) {
         Notification notif = new Notification.Builder(mContext, TEST_CHANNEL_ID)
                 .setContentTitle("Title")
                 .setSmallIcon(R.drawable.ic_person)
@@ -71,7 +79,7 @@
         StatusBarNotification sbn = new StatusBarNotification(
                 TEST_PACKAGE_NAME /* pkg */,
                 TEST_PACKAGE_NAME,
-                mId++,
+                id,
                 null /* tag */,
                 0, /* uid */
                 0 /* initialPid */,
@@ -79,7 +87,7 @@
                 new UserHandle(ActivityManager.getCurrentUser()),
                 null /* overrideGroupKey */,
                 0 /* postTime */);
-        NotificationEntry entry = new NotificationEntry(sbn);
+        NotificationEntry entry = NotificationEntry.buildForTest(sbn);
         ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
         entry.setRow(row);
         when(row.getEntry()).thenReturn(entry);
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 186a8c7..45cd1e1 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
@@ -86,7 +86,7 @@
         Notification n = new Notification.Builder(getContext(), "a").build();
         StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
                 UserHandle.of(0), null, 0);
-        NotificationEntry entry = new NotificationEntry(sbn);
+        NotificationEntry entry = NotificationEntry.buildForTest(sbn);
         mCommandQueue.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_EXPAND, 0,
                 false /* animate */);
         TestableLooper.get(this).processAllMessages();
@@ -100,7 +100,7 @@
         Notification n = new Notification.Builder(getContext(), "a").build();
         StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
                 UserHandle.of(0), null, 0);
-        NotificationEntry entry = new NotificationEntry(sbn);
+        NotificationEntry entry = NotificationEntry.buildForTest(sbn);
         mCommandQueue.disable(DEFAULT_DISPLAY, 0, StatusBarManager.DISABLE2_NOTIFICATION_SHADE,
                 false /* animate */);
         TestableLooper.get(this).processAllMessages();
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 fa235bd..7fbf183 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
@@ -418,7 +418,7 @@
                 .build();
         StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
                 UserHandle.of(0), null, 0);
-        NotificationEntry entry = new NotificationEntry(sbn);
+        NotificationEntry entry = NotificationEntry.buildForTest(sbn);
         entry.importance = IMPORTANCE_HIGH;
 
         assertTrue(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
@@ -439,7 +439,7 @@
                 .build();
         StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
                 UserHandle.of(0), null, 0);
-        NotificationEntry entry = new NotificationEntry(sbn);
+        NotificationEntry entry = NotificationEntry.buildForTest(sbn);
         entry.importance = IMPORTANCE_HIGH;
 
         assertFalse(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
@@ -456,7 +456,7 @@
         Notification n = new Notification.Builder(getContext(), "a").build();
         StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
                 UserHandle.of(0), null, 0);
-        NotificationEntry entry = new NotificationEntry(sbn);
+        NotificationEntry entry = NotificationEntry.buildForTest(sbn);
         entry.suppressedVisualEffects = SUPPRESSED_EFFECT_PEEK;
         entry.importance = IMPORTANCE_HIGH;
 
@@ -474,7 +474,7 @@
         Notification n = new Notification.Builder(getContext(), "a").build();
         StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
                 UserHandle.of(0), null, 0);
-        NotificationEntry entry = new NotificationEntry(sbn);
+        NotificationEntry entry = NotificationEntry.buildForTest(sbn);
         entry.importance = IMPORTANCE_HIGH;
 
         assertTrue(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/InflatedSmartRepliesTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/InflatedSmartRepliesTest.java
index 2462fb3..bda0e39 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/InflatedSmartRepliesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/InflatedSmartRepliesTest.java
@@ -88,7 +88,7 @@
 
         when(mNotification.getAllowSystemGeneratedContextualActions()).thenReturn(true);
         when(mStatusBarNotification.getNotification()).thenReturn(mNotification);
-        mEntry = new NotificationEntry(mStatusBarNotification);
+        mEntry = NotificationEntry.buildForTest(mStatusBarNotification);
         when(mSmartReplyConstants.isEnabled()).thenReturn(true);
         mActionIcon = Icon.createWithResource(mContext, R.drawable.ic_person);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
index 0cb5754..b59bac1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
@@ -140,7 +140,7 @@
         StatusBarNotification sbn = mock(StatusBarNotification.class);
         when(sbn.getNotification()).thenReturn(mNotification);
         when(sbn.getKey()).thenReturn(TEST_NOTIFICATION_KEY);
-        mEntry = new NotificationEntry(sbn);
+        mEntry = NotificationEntry.buildForTest(sbn);
 
         mActionIcon = Icon.createWithResource(mContext, R.drawable.ic_person);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFake.java b/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFake.java
new file mode 100644
index 0000000..426aba0
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFake.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 com.android.systemui.util;
+
+import android.content.Context;
+import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.OnPropertiesChangedListener;
+import android.provider.DeviceConfig.Properties;
+import android.util.Pair;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+/**
+ * A Fake of {@link DeviceConfigProxy} useful for testing.
+ *
+ * No properties are set by default. No calls to {@link DeviceConfig} are made. Be sure to set any
+ * properties you rely on ahead of time in your test.
+ */
+public class DeviceConfigProxyFake extends DeviceConfigProxy {
+
+    private List<Pair<Executor, OnPropertiesChangedListener>> mListeners = new ArrayList<>();
+    private Map<String, Map<String, String>> mDefaultProperties = new HashMap<>();
+    private Map<String, Map<String, String>> mProperties = new HashMap<>();
+
+    public DeviceConfigProxyFake() {
+    }
+
+    @Override
+    public void addOnPropertiesChangedListener(
+            String namespace, Executor executor,
+            OnPropertiesChangedListener onPropertiesChangedListener) {
+        mListeners.add(Pair.create(executor, onPropertiesChangedListener));
+    }
+
+    @Override
+    public void removeOnPropertiesChangedListener(
+            OnPropertiesChangedListener onPropertiesChangedListener) {
+        mListeners.removeIf(listener -> {
+            if (listener == null) {
+                return false;
+            }
+            return listener.second.equals(onPropertiesChangedListener);
+        });
+    }
+
+    @Override
+    public boolean setProperty(String namespace, String name, String value, boolean makeDefault) {
+        setPropertyInternal(namespace, name, value, mProperties);
+        if (makeDefault) {
+            setPropertyInternal(namespace, name, value, mDefaultProperties);
+        }
+
+        for (Pair<Executor, OnPropertiesChangedListener> listener : mListeners) {
+            listener.first.execute(() -> listener.second.onPropertiesChanged(
+                    new Properties(namespace, mProperties.get(namespace))));
+        }
+        return true;
+    }
+
+    private void setPropertyInternal(String namespace, String name, String value,
+            Map<String, Map<String, String>> properties) {
+        properties.putIfAbsent(namespace, new HashMap<>());
+        properties.get(namespace).put(name, value);
+    }
+
+    @Override
+    public void enforceReadPermission(Context context, String namespace) {
+        // no-op
+    }
+
+    private Properties propsForNamespaceAndName(String namespace, String name) {
+        if (mProperties.containsKey(namespace) && mProperties.get(namespace).containsKey(name)) {
+            return new Properties(namespace, mProperties.get(namespace));
+        }
+        if (mDefaultProperties.containsKey(namespace)) {
+            return new Properties(namespace, mDefaultProperties.get(namespace));
+        }
+
+        return null;
+    }
+
+    @Override
+    public boolean getBoolean(String namespace, String name, boolean defaultValue) {
+        Properties props = propsForNamespaceAndName(namespace, name);
+        if (props != null) {
+            return props.getBoolean(name, defaultValue);
+        }
+
+        return defaultValue;
+    }
+
+    @Override
+    public int getInt(String namespace, String name, int defaultValue) {
+        Properties props = propsForNamespaceAndName(namespace, name);
+        if (props != null) {
+            return props.getInt(name, defaultValue);
+        }
+
+        return defaultValue;
+    }
+
+    @Override
+    public long getLong(String namespace, String name, long defaultValue) {
+        Properties props = propsForNamespaceAndName(namespace, name);
+        if (props != null) {
+            return props.getLong(name, defaultValue);
+        }
+
+        return defaultValue;
+    }
+
+    @Override
+    public String getProperty(String namespace, String name) {
+        return getString(namespace, name, null);
+    }
+
+    @Override
+    public String getString(String namespace, String name, String defaultValue) {
+        Properties props = propsForNamespaceAndName(namespace, name);
+        if (props != null) {
+            return props.getString(name, defaultValue);
+        }
+
+        return defaultValue;
+    }
+
+    @Override
+    public void resetToDefaults(int resetMode, String namespace) {
+        if (mProperties.containsKey(namespace)) {
+            mProperties.get(namespace).clear();
+        }
+    }
+}
diff --git a/services/Android.bp b/services/Android.bp
index 27f8d36..6953e86 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -63,6 +63,5 @@
 
 platform_compat_config {
     name: "services-platform-compat-config",
-    prefix: "services",
     src: ":services",
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index d8b7e3a..a338b90 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -66,12 +66,6 @@
     // Tag for logging received events.
     private static final String LOG_TAG = "TouchExplorer";
 
-    // States this explorer can be in.
-    private static final int STATE_TOUCH_EXPLORING = 0x00000001;
-    private static final int STATE_DRAGGING = 0x00000002;
-    private static final int STATE_DELEGATING = 0x00000004;
-    private static final int STATE_GESTURE_DETECTING = 0x00000005;
-
     // The maximum of the cosine between the vectors of two moving
     // pointers so they can be considered moving in the same direction.
     private static final float MAX_DRAGGING_ANGLE_COS = 0.525321989f; // cos(pi/4)
@@ -248,7 +242,13 @@
             return;
         }
 
-        if (mState.isTouchExploring()) {
+        // TODO: extract the below functions into separate handlers for each state.
+        // Right now the number of functions and number of states make the code messy.
+        if (mState.isClear()) {
+            handleMotionEventStateClear(event, rawEvent, policyFlags);
+        } else if (mState.isTouchInteracting()) {
+            handleMotionEventStateTouchInteracting(event, rawEvent, policyFlags);
+        } else if (mState.isTouchExploring()) {
             handleMotionEventStateTouchExploring(event, rawEvent, policyFlags);
         } else if (mState.isDragging()) {
             handleMotionEventStateDragging(event, policyFlags);
@@ -286,8 +286,8 @@
 
     @Override
     public void onDoubleTapAndHold(MotionEvent event, int policyFlags) {
-        // Ignore the event if we aren't touch exploring.
-        if (!mState.isTouchExploring()) {
+        // Ignore the event if we aren't touch interacting.
+        if (!mState.isTouchInteracting()) {
             return;
         }
 
@@ -304,8 +304,7 @@
 
     @Override
     public boolean onDoubleTap(MotionEvent event, int policyFlags) {
-        // Ignore the event if we aren't touch exploring.
-        if (!mState.isTouchExploring()) {
+        if (!mState.isTouchInteracting()) {
             return false;
         }
 
@@ -380,6 +379,94 @@
     }
 
     /**
+     * Handles a motion event in the clear state i.e. no fingers are touching the screen.
+     */
+    private void handleMotionEventStateClear(
+            MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        switch (event.getActionMasked()) {
+            // The only way to leave the clear state is for a pointer to go down.
+            case MotionEvent.ACTION_DOWN:
+                handleActionDown(event, policyFlags);
+                break;
+            default:
+                // Some other nonsensical event.
+                break;
+        }
+    }
+
+    /**
+     * Handles ACTION_DOWN while in the clear or touch interacting states. This event represents the
+     * first finger touching the screen.
+     */
+    private void handleActionDown(MotionEvent event, int policyFlags) {
+        mAms.onTouchInteractionStart();
+
+        // If we still have not notified the user for the last
+        // touch, we figure out what to do. If were waiting
+        // we resent the delayed callback and wait again.
+        mSendHoverEnterAndMoveDelayed.cancel();
+        mSendHoverExitDelayed.cancel();
+
+        // If a touch exploration gesture is in progress send events for its end.
+        if (mState.isTouchExploring()) {
+            sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
+        }
+
+        // Avoid duplicated TYPE_TOUCH_INTERACTION_START event when 2nd tap of double
+        // tap.
+        if (!mGestureDetector.firstTapDetected() && mState.isClear()) {
+            mSendTouchExplorationEndDelayed.forceSendAndRemove();
+            mSendTouchInteractionEndDelayed.forceSendAndRemove();
+            sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_START);
+        } else {
+            // Let gesture to handle to avoid duplicated TYPE_TOUCH_INTERACTION_END event.
+            mSendTouchInteractionEndDelayed.cancel();
+        }
+
+        if (!mGestureDetector.firstTapDetected() && !mState.isTouchExploring()) {
+            if (!mSendHoverEnterAndMoveDelayed.isPending()) {
+                // Queue a delayed transition to STATE_TOUCH_EXPLORING.
+                // If we do not detect that this is a gesture, delegation or drag the transition
+                // will fire by default.
+                // The idea is to avoid getting stuck in STATE_TOUCH_INTERACTING
+                final int pointerId = mReceivedPointerTracker.getPrimaryPointerId();
+                final int pointerIdBits = (1 << pointerId);
+                mSendHoverEnterAndMoveDelayed.post(event, pointerIdBits, policyFlags);
+            } else {
+                // Cache the event until we discern exploration from gesturing.
+                mSendHoverEnterAndMoveDelayed.addEvent(event);
+            }
+        }
+    }
+
+    /**
+     * Handles a motion event in touch interacting state.
+     *
+     * @param event The event to be handled.
+     * @param rawEvent The raw (unmodified) motion event.
+     * @param policyFlags The policy flags associated with the event.
+     */
+    private void handleMotionEventStateTouchInteracting(
+            MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        switch (event.getActionMasked()) {
+            case MotionEvent.ACTION_DOWN:
+                // Continue the previous interaction.
+                mSendTouchInteractionEndDelayed.cancel();
+                handleActionDown(event, policyFlags);
+                break;
+            case MotionEvent.ACTION_POINTER_DOWN:
+                handleActionPointerDown();
+                break;
+            case MotionEvent.ACTION_MOVE:
+                handleActionMoveStateTouchInteracting(event, rawEvent, policyFlags);
+                break;
+            case MotionEvent.ACTION_UP:
+                handleActionUp(event, policyFlags);
+                break;
+        }
+    }
+
+    /**
      * Handles a motion event in touch exploring state.
      *
      * @param event The event to be handled.
@@ -390,60 +477,19 @@
             MotionEvent event, MotionEvent rawEvent, int policyFlags) {
         switch (event.getActionMasked()) {
             case MotionEvent.ACTION_DOWN:
-                handleActionDownStateTouchExploring(event, policyFlags);
+                // We should have already received ACTION_DOWN. Ignore.
                 break;
             case MotionEvent.ACTION_POINTER_DOWN:
-                handleActionPointerDownStateTouchExploring();
+                handleActionPointerDown();
                 break;
             case MotionEvent.ACTION_MOVE:
                 handleActionMoveStateTouchExploring(event, rawEvent, policyFlags);
                 break;
             case MotionEvent.ACTION_UP:
-                handleActionUpStateTouchExploring(event, policyFlags);
+                handleActionUp(event, policyFlags);
                 break;
-        }
-    }
-
-    /**
-     * Handles ACTION_DOWN while in the default touch exploring state. This event represents the
-     * first finger touching the screen.
-     */
-    private void handleActionDownStateTouchExploring(MotionEvent event, int policyFlags) {
-        mAms.onTouchInteractionStart();
-
-        // If we still have not notified the user for the last
-        // touch, we figure out what to do. If were waiting
-        // we resent the delayed callback and wait again.
-        mSendHoverEnterAndMoveDelayed.cancel();
-        mSendHoverExitDelayed.cancel();
-
-        // If a touch exploration gesture is in progress send events for its end.
-        if (mState.isTouchExplorationInProgress()) {
-            sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
-        }
-
-        // Avoid duplicated TYPE_TOUCH_INTERACTION_START event when 2nd tap of double
-        // tap.
-        if (!mGestureDetector.firstTapDetected()) {
-            mSendTouchExplorationEndDelayed.forceSendAndRemove();
-            mSendTouchInteractionEndDelayed.forceSendAndRemove();
-            sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_START);
-        } else {
-            // Let gesture to handle to avoid duplicated TYPE_TOUCH_INTERACTION_END event.
-            mSendTouchInteractionEndDelayed.cancel();
-        }
-
-        if (!mGestureDetector.firstTapDetected() && !mState.isTouchExplorationInProgress()) {
-            if (!mSendHoverEnterAndMoveDelayed.isPending()) {
-                // Deliver hover enter with a delay to have a chance
-                // to detect what the user is trying to do.
-                final int pointerId = mReceivedPointerTracker.getPrimaryPointerId();
-                final int pointerIdBits = (1 << pointerId);
-                mSendHoverEnterAndMoveDelayed.post(event, true, pointerIdBits, policyFlags);
-            } else {
-                // Cache the event until we discern exploration from gesturing.
-                mSendHoverEnterAndMoveDelayed.addEvent(event);
-            }
+            default:
+                break;
         }
     }
 
@@ -451,7 +497,7 @@
      * Handles ACTION_POINTER_DOWN when in the touch exploring state. This event represents an
      * additional finger touching the screen.
      */
-    private void handleActionPointerDownStateTouchExploring() {
+    private void handleActionPointerDown() {
         // Another finger down means that if we have not started to deliver
         // hover events, we will not have to. The code for ACTION_MOVE will
         // decide what we will actually do next.
@@ -459,10 +505,10 @@
         mSendHoverExitDelayed.cancel();
     }
     /**
-     * Handles ACTION_MOVE while in the initial touch exploring state. This is where transitions to
+     * Handles ACTION_MOVE while in the touch interacting state. This is where transitions to
      * delegating and dragging states are handled.
      */
-    private void handleActionMoveStateTouchExploring(
+    private void handleActionMoveStateTouchInteracting(
             MotionEvent event, MotionEvent rawEvent, int policyFlags) {
         final int pointerId = mReceivedPointerTracker.getPrimaryPointerId();
         final int pointerIndex = event.findPointerIndex(pointerId);
@@ -474,41 +520,14 @@
                 if (mSendHoverEnterAndMoveDelayed.isPending()) {
                     // Cache the event until we discern exploration from gesturing.
                     mSendHoverEnterAndMoveDelayed.addEvent(event);
-                } else if (mState.isTouchExplorationInProgress()) {
-                    sendTouchExplorationGestureStartAndHoverEnterIfNeeded(policyFlags);
-                    sendMotionEvent(
-                            event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits, policyFlags);
                 }
                 break;
             case 2:
+                // Make sure we don't have any pending transitions to touch exploration
+                mSendHoverEnterAndMoveDelayed.cancel();
+                mSendHoverExitDelayed.cancel();
                 // More than one pointer so the user is not touch exploring
                 // and now we have to decide whether to delegate or drag.
-                if (mSendHoverEnterAndMoveDelayed.isPending()) {
-                    // We have not started sending events so cancel
-                    // scheduled sending events.
-                    mSendHoverEnterAndMoveDelayed.cancel();
-                    mSendHoverExitDelayed.cancel();
-                } else if (mState.isTouchExplorationInProgress()) {
-                    // If the user is touch exploring the second pointer may be
-                    // performing a double tap to activate an item without need
-                    // for the user to lift his exploring finger.
-                    // It is *important* to use the distance traveled by the pointers
-                    // on the screen which may or may not be magnified.
-                    final float deltaX =
-                            mReceivedPointerTracker.getReceivedPointerDownX(pointerId)
-                                    - rawEvent.getX(pointerIndex);
-                    final float deltaY =
-                            mReceivedPointerTracker.getReceivedPointerDownY(pointerId)
-                                    - rawEvent.getY(pointerIndex);
-                    final double moveDelta = Math.hypot(deltaX, deltaY);
-                    if (moveDelta < mDoubleTapSlop) {
-                        break;
-                    }
-                    // We are sending events so send exit and gesture
-                    // end since we transition to another state.
-                    sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
-                }
-
                 // Remove move history before send injected non-move events
                 event = MotionEvent.obtainNoHistory(event);
                 if (isDraggingGesture(event)) {
@@ -525,19 +544,6 @@
                 }
                 break;
             default:
-                // More than one pointer so the user is not touch exploring
-                // and now we have to decide whether to delegate or drag.
-                if (mSendHoverEnterAndMoveDelayed.isPending()) {
-                    // We have not started sending events so cancel
-                    // scheduled sending events.
-                    mSendHoverEnterAndMoveDelayed.cancel();
-                    mSendHoverExitDelayed.cancel();
-                } else {
-                    // We are sending events so send exit and gesture
-                    // end since we transition to another state.
-                    sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
-                }
-
                 // More than two pointers are delegated to the view hierarchy.
                 mState.startDelegating();
                 event = MotionEvent.obtainNoHistory(event);
@@ -547,14 +553,13 @@
     }
 
     /**
-     * Handles ACTION_UP while in the initial touch exploring state. This event represents all
-     * fingers being lifted from the screen.
+     * Handles ACTION_UP while in the touch interacting state. This event represents all fingers
+     * being lifted from the screen.
      */
-    private void handleActionUpStateTouchExploring(MotionEvent event, int policyFlags) {
+    private void handleActionUp(MotionEvent event, int policyFlags) {
         mAms.onTouchInteractionEnd();
         final int pointerId = event.getPointerId(event.getActionIndex());
         final int pointerIdBits = (1 << pointerId);
-
         if (mSendHoverEnterAndMoveDelayed.isPending()) {
             // If we have not delivered the enter schedule an exit.
             mSendHoverExitDelayed.post(event, pointerIdBits, policyFlags);
@@ -562,13 +567,69 @@
             // The user is touch exploring so we send events for end.
             sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
         }
-
         if (!mSendTouchInteractionEndDelayed.isPending()) {
             mSendTouchInteractionEndDelayed.post();
         }
     }
 
     /**
+     * Handles move events while touch exploring. this is also where we drag or delegate based on
+     * the number of fingers moving on the screen.
+     */
+    private void handleActionMoveStateTouchExploring(
+            MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        final int pointerId = mReceivedPointerTracker.getPrimaryPointerId();
+        final int pointerIdBits = (1 << pointerId);
+        final int pointerIndex = event.findPointerIndex(pointerId);
+        switch (event.getPointerCount()) {
+            case 1:
+            // Touch exploration.
+                sendTouchExplorationGestureStartAndHoverEnterIfNeeded(policyFlags);
+                sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits, policyFlags);
+                break;
+            case 2:
+                if (mSendHoverEnterAndMoveDelayed.isPending()) {
+                    // We have not started sending events so cancel
+                    // scheduled sending events.
+                    mSendHoverEnterAndMoveDelayed.cancel();
+                    mSendHoverExitDelayed.cancel();
+                }
+                // If the user is touch exploring the second pointer may be
+                // performing a double tap to activate an item without need
+                // for the user to lift his exploring finger.
+                // It is *important* to use the distance traveled by the pointers
+                // on the screen which may or may not be magnified.
+                final float deltaX =
+                        mReceivedPointerTracker.getReceivedPointerDownX(pointerId)
+                                - rawEvent.getX(pointerIndex);
+                final float deltaY =
+                        mReceivedPointerTracker.getReceivedPointerDownY(pointerId)
+                                - rawEvent.getY(pointerIndex);
+                final double moveDelta = Math.hypot(deltaX, deltaY);
+                if (moveDelta > mDoubleTapSlop) {
+                    // The user is trying to either delegate or drag.
+                    handleActionMoveStateTouchInteracting(event, rawEvent, policyFlags);
+                } else {
+                    // Otherwise the double tap will be handled by the gesture detector.
+                    sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
+                }
+                break;
+            default:
+                // Three or more fingers is  something other than touch exploration.
+                if (mSendHoverEnterAndMoveDelayed.isPending()) {
+                    // We have not started sending events so cancel
+                    // scheduled sending events.
+                    mSendHoverEnterAndMoveDelayed.cancel();
+                    mSendHoverExitDelayed.cancel();
+                } else {
+                    sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
+                }
+                handleActionMoveStateTouchInteracting(event, rawEvent, policyFlags);
+                break;
+        }
+    }
+
+    /**
      * Handles a motion event in dragging state.
      *
      * @param event The event to be handled.
@@ -670,7 +731,6 @@
                     // Send an event to the end of the drag gesture.
                     sendMotionEvent(event, MotionEvent.ACTION_UP, pointerIdBits, policyFlags);
                 }
-                mState.startTouchExploring();
             } break;
         }
     }
@@ -697,7 +757,6 @@
                 mAms.onTouchInteractionEnd();
                 sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
 
-                mState.startTouchExploring();
             } break;
             default: {
                 // Deliver the event.
@@ -717,7 +776,6 @@
         }
 
         mExitGestureDetectionModeDelayed.cancel();
-        mState.startTouchExploring();
     }
 
     /**
@@ -731,8 +789,13 @@
             AccessibilityEvent event = AccessibilityEvent.obtain(type);
             event.setWindowId(mAms.getActiveWindowId());
             accessibilityManager.sendAccessibilityEvent(event);
-            mState.onInjectedAccessibilityEvent(type);
+            if (DEBUG) {
+                Slog.d(
+                        LOG_TAG,
+                        "Sending accessibility event" + AccessibilityEvent.eventTypeToString(type));
+            }
         }
+        mState.onInjectedAccessibilityEvent(type);
     }
 
     /**
@@ -915,6 +978,10 @@
                 MAX_DRAGGING_ANGLE_COS);
     }
 
+    public TouchState getState() {
+        return mState;
+    }
+
     /**
      * Class for delayed exiting from gesture detecting mode.
      */
@@ -947,8 +1014,7 @@
         private int mPointerIdBits;
         private int mPolicyFlags;
 
-        public void post(MotionEvent event, boolean touchExplorationInProgress,
-                int pointerIdBits, int policyFlags) {
+        public void post(MotionEvent event, int pointerIdBits, int policyFlags) {
             cancel();
             addEvent(event);
             mPointerIdBits = pointerIdBits;
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
index 820c1a7..17e969a 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
@@ -41,20 +41,33 @@
     public static final int ALL_POINTER_ID_BITS = 0xFFFFFFFF;
 
     // States that the touch explorer can be in.
-    public static final int STATE_TOUCH_EXPLORING = 0x00000001;
-    public static final int STATE_DRAGGING = 0x00000002;
-    public static final int STATE_DELEGATING = 0x00000003;
-    public static final int STATE_GESTURE_DETECTING = 0x00000004;
+    // In the clear state the user is not touching the screen.
+    public static final int STATE_CLEAR = 0;
+    // The user is touching the screen and we are trying to figure out their intent.
+    // This state gets its name from the TYPE_TOUCH_INTERACTION start and end accessibility events.
+    public static final int STATE_TOUCH_INTERACTING = 1;
+    // The user is explicitly exploring the screen.
+    public static final int STATE_TOUCH_EXPLORING = 2;
+    // the user is dragging with two fingers.
+    public static final int STATE_DRAGGING = 3;
+    // The user is performing some other two finger gesture which we pass through to the view
+    // hierarchy as a one-finger gesture e.g. two-finger scrolling.
+    public static final int STATE_DELEGATING = 4;
+    // The user is performing something that might be a gesture.
+    public static final int STATE_GESTURE_DETECTING = 5;
 
-    @IntDef({STATE_TOUCH_EXPLORING, STATE_DRAGGING, STATE_DELEGATING, STATE_GESTURE_DETECTING})
+    @IntDef({
+        STATE_CLEAR,
+        STATE_TOUCH_INTERACTING,
+        STATE_TOUCH_EXPLORING,
+        STATE_DRAGGING,
+        STATE_DELEGATING,
+        STATE_GESTURE_DETECTING
+    })
     public @interface State {}
 
     // The current state of the touch explorer.
-    private int mState = STATE_TOUCH_EXPLORING;
-    // Whether touch exploration is in progress.
-    // TODO: Add separate states to represent  intend detection and actual touch exploration so that
-    // only one variable describes the state.
-    private boolean mTouchExplorationInProgress;
+    private int mState = STATE_CLEAR;
     // Helper class to track received pointers.
     // Todo: collapse or hide this class so multiple classes don't modify it.
     private final ReceivedPointerTracker mReceivedPointerTracker;
@@ -69,8 +82,7 @@
 
     /** Clears the internal shared state. */
     public void clear() {
-        mState = STATE_TOUCH_EXPLORING;
-        mTouchExplorationInProgress = false;
+        setState(STATE_CLEAR);
         // Reset the pointer trackers.
         mReceivedPointerTracker.clear();
         mInjectedPointerTracker.clear();
@@ -94,18 +106,33 @@
         mReceivedPointerTracker.onMotionEvent(rawEvent);
     }
 
-    /**
-     * Updates the state in response to an accessibility event being sent from TouchExplorer.
-     *
-     * @param type The event type.
-     */
     public void onInjectedAccessibilityEvent(int type) {
+        // The below state transitions go here because the related events are often sent on a
+        // delay.
+        // This allows state to accurately reflect the state in the moment.
+        // TODO: replaced the delayed event senders with delayed state transitions
+        // so that state transitions trigger events rather than events triggering state
+        // transitions.
         switch (type) {
+            case AccessibilityEvent.TYPE_TOUCH_INTERACTION_START:
+                startTouchInteracting();
+                break;
+            case AccessibilityEvent.TYPE_TOUCH_INTERACTION_END:
+                clear();
+                break;
             case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START:
-                mTouchExplorationInProgress = true;
+                startTouchExploring();
                 break;
             case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END:
-                mTouchExplorationInProgress = false;
+                startTouchInteracting();
+                break;
+            case AccessibilityEvent.TYPE_GESTURE_DETECTION_START:
+                startGestureDetecting();
+                break;
+            case AccessibilityEvent.TYPE_GESTURE_DETECTION_END:
+                startTouchInteracting();
+                break;
+            default:
                 break;
         }
     }
@@ -117,6 +144,7 @@
 
     /** Transitions to a new state. */
     public void setState(@State int state) {
+        if (mState == state) return;
         if (DEBUG) {
             Slog.i(LOG_TAG, getStateSymbolicName(mState) + "->" + getStateSymbolicName(state));
         }
@@ -159,26 +187,32 @@
         setState(STATE_DRAGGING);
     }
 
-    public boolean isTouchExplorationInProgress() {
-        return mTouchExplorationInProgress;
+    public boolean isTouchInteracting() {
+        return mState == STATE_TOUCH_INTERACTING;
     }
 
-    public void setTouchExplorationInProgress(boolean touchExplorationInProgress) {
-        mTouchExplorationInProgress = touchExplorationInProgress;
+    /**
+     * Transitions to the touch interacting state, where we attempt to figure out what the user is
+     * doing.
+     */
+    public void startTouchInteracting() {
+        setState(STATE_TOUCH_INTERACTING);
     }
 
+    public boolean isClear() {
+        return mState == STATE_CLEAR;
+    }
     /** Returns a string representation of the current state. */
     public String toString() {
-        return "TouchState { "
-                + "mState: "
-                + getStateSymbolicName(mState)
-                + ", mTouchExplorationInProgress"
-                + mTouchExplorationInProgress
-                + " }";
+        return "TouchState { " + "mState: " + getStateSymbolicName(mState) + " }";
     }
     /** Returns a string representation of the specified state. */
     public static String getStateSymbolicName(int state) {
         switch (state) {
+            case STATE_CLEAR:
+                return "STATE_CLEAR";
+            case STATE_TOUCH_INTERACTING:
+                return "STATE_TOUCH_INTERACTING";
             case STATE_TOUCH_EXPLORING:
                 return "STATE_TOUCH_EXPLORING";
             case STATE_DRAGGING:
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java
index d7e68f8..5844f98 100644
--- a/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java
@@ -23,6 +23,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.prediction.AppPredictionContext;
 import android.app.prediction.AppPredictionSessionId;
 import android.app.prediction.AppTargetEvent;
@@ -61,7 +62,8 @@
 
     public AppPredictionManagerService(Context context) {
         super(context, new FrameworkResourcesServiceNameResolver(context,
-                com.android.internal.R.string.config_defaultAppPredictionService), null);
+                com.android.internal.R.string.config_defaultAppPredictionService), null,
+                PACKAGE_UPDATE_POLICY_NO_REFRESH | PACKAGE_RESTART_POLICY_NO_REFRESH);
         mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
     }
 
@@ -80,6 +82,22 @@
         getContext().enforceCallingPermission(MANAGE_APP_PREDICTIONS, TAG);
     }
 
+    @Override // from AbstractMasterSystemService
+    protected void onServicePackageUpdatedLocked(@UserIdInt int userId) {
+        final AppPredictionPerUserService service = peekServiceForUserLocked(userId);
+        if (service != null) {
+            service.onPackageUpdatedLocked();
+        }
+    }
+
+    @Override // from AbstractMasterSystemService
+    protected void onServicePackageRestartedLocked(@UserIdInt int userId) {
+        final AppPredictionPerUserService service = peekServiceForUserLocked(userId);
+        if (service != null) {
+            service.onPackageRestartedLocked();
+        }
+    }
+
     @Override
     protected int getMaximumTemporaryServiceDurationMs() {
         return MAX_TEMP_SERVICE_DURATION_MS;
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
index 03c4542..4f49fb7 100644
--- a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
@@ -251,6 +251,40 @@
         // Do nothing, eventually the system will bind to the remote service again...
     }
 
+    void onPackageUpdatedLocked() {
+        if (isDebug()) {
+            Slog.v(TAG, "onPackageUpdatedLocked()");
+        }
+        destroyAndRebindRemoteService();
+    }
+
+    void onPackageRestartedLocked() {
+        if (isDebug()) {
+            Slog.v(TAG, "onPackageRestartedLocked()");
+        }
+        destroyAndRebindRemoteService();
+    }
+
+    private void destroyAndRebindRemoteService() {
+        if (mRemoteService == null) {
+            return;
+        }
+
+        if (isDebug()) {
+            Slog.d(TAG, "Destroying the old remote service.");
+        }
+        mRemoteService.destroy();
+        mRemoteService = null;
+
+        mRemoteService = getRemoteServiceLocked();
+        if (mRemoteService != null) {
+            if (isDebug()) {
+                Slog.d(TAG, "Rebinding to the new remote service.");
+            }
+            mRemoteService.reconnect();
+        }
+    }
+
     /**
      * Called after the remote service connected, it's used to restore state from a 'zombie'
      * service (i.e., after it died).
diff --git a/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java b/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java
index c82e7a0..04e0e7f 100644
--- a/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java
+++ b/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java
@@ -135,6 +135,13 @@
     }
 
     /**
+     * Schedules a request to bind to the remote service.
+     */
+    public void reconnect() {
+        super.scheduleBind();
+    }
+
+    /**
      * Failure callback
      */
     public interface RemoteAppPredictionServiceCallbacks
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 6b7c3e6..c689ed1 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -212,8 +212,7 @@
                 (u, s, t) -> onAugmentedServiceNameChanged(u, s, t));
 
         if (mSupportedSmartSuggestionModes != AutofillManager.FLAG_SMART_SUGGESTION_OFF) {
-            final UserManager um = getContext().getSystemService(UserManager.class);
-            final List<UserInfo> users = um.getUsers();
+            final List<UserInfo> users = getSupportedUsers();
             for (int i = 0; i < users.size(); i++) {
                 final int userId = users.get(i).id;
                 // Must eager load the services so they bind to the augmented autofill service
@@ -325,6 +324,11 @@
     }
 
     @Override // from SystemService
+    public boolean isSupported(UserInfo userInfo) {
+        return userInfo.isFull() || userInfo.isManagedProfile();
+    }
+
+    @Override // from SystemService
     public void onSwitchUser(int userHandle) {
         if (sDebug) Slog.d(TAG, "Hiding UI when user switched");
         mUi.hideAll(null);
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 48f16ac..256ca50 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2419,6 +2419,7 @@
                     Slog.v(TAG, "entered on virtual child " + id + ": " + virtualBounds);
                 }
 
+                final boolean isSameViewEntered = Objects.equals(mCurrentViewId, viewState.id);
                 // Update the view states first...
                 mCurrentViewId = viewState.id;
                 if (value != null) {
@@ -2451,6 +2452,10 @@
                     hideAugmentedAutofillLocked(viewState);
                 }
 
+                if (isSameViewEntered) {
+                    return;
+                }
+
                 // If the ViewState is ready to be displayed, onReady() will be called.
                 viewState.update(value, virtualBounds, flags);
                 break;
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 5c6258f..c8dbb36 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -147,8 +147,7 @@
             mRequestsHistory = null;
         }
 
-        final UserManager um = getContext().getSystemService(UserManager.class);
-        final List<UserInfo> users = um.getUsers();
+        final List<UserInfo> users = getSupportedUsers();
         for (int i = 0; i < users.size(); i++) {
             final int userId = users.get(i).id;
             final boolean disabled = !isEnabledBySettings(userId);
@@ -174,6 +173,11 @@
     }
 
     @Override // from SystemService
+    public boolean isSupported(UserInfo userInfo) {
+        return userInfo.isFull() || userInfo.isManagedProfile();
+    }
+
+    @Override // from SystemService
     public void onStart() {
         publishBinderService(CONTENT_CAPTURE_MANAGER_SERVICE,
                 new ContentCaptureManagerServiceStub());
@@ -336,8 +340,7 @@
         if (verbose) {
             Slog.v(mTag, "setDisabledByDeviceConfig(): explicitlyEnabled=" + explicitlyEnabled);
         }
-        final UserManager um = getContext().getSystemService(UserManager.class);
-        final List<UserInfo> users = um.getUsers();
+        final List<UserInfo> users = getSupportedUsers();
 
         final boolean newDisabledValue;
 
diff --git a/services/core/Android.bp b/services/core/Android.bp
index c838c60..1643221 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -53,7 +53,7 @@
         "android.hardware.contexthub-V1.0-java",
         "android.hidl.manager-V1.2-java",
         "dnsresolver_aidl_interface-V2-java",
-        "netd_aidl_interface-V2-java",
+        "netd_aidl_interface-java",
         "netd_event_listener_interface-java",
     ],
 }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index e67ccc4..2a2dc3d 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1102,7 +1102,7 @@
         mSettingsObserver = new SettingsObserver(mContext, mHandler);
         registerSettingsCallbacks();
 
-        final DataConnectionStats dataConnectionStats = new DataConnectionStats(mContext);
+        final DataConnectionStats dataConnectionStats = new DataConnectionStats(mContext, mHandler);
         dataConnectionStats.startMonitoring();
 
         mKeepaliveTracker = new KeepaliveTracker(mContext, mHandler);
@@ -4551,7 +4551,7 @@
                     Slog.w(TAG, "VPN for user " + user + " not ready yet. Skipping lockdown");
                     return false;
                 }
-                setLockdownTracker(new LockdownVpnTracker(mContext, mNMS, this, vpn, profile));
+                setLockdownTracker(new LockdownVpnTracker(mContext, this, mHandler, vpn, profile));
             } else {
                 setLockdownTracker(null);
             }
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 59e0a28..9efaad8 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -1008,11 +1008,15 @@
 
     @Override
     public void startTethering(String[] dhcpRange) {
+        startTetheringWithConfiguration(true, dhcpRange);
+    }
+
+    @Override
+    public void startTetheringWithConfiguration(boolean usingLegacyDnsProxy, String[] dhcpRange) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
         // an odd number of addrs will fail
-
         try {
-            mNetdService.tetherStart(dhcpRange);
+            mNetdService.tetherStartWithConfiguration(usingLegacyDnsProxy, dhcpRange);
         } catch (RemoteException | ServiceSpecificException e) {
             throw new IllegalStateException(e);
         }
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index ea3dd3d..73ec561 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -131,6 +131,10 @@
     @GuardedBy("mLock")
     private long mUptimeAtLastStateSync;
 
+    private final Runnable mSyncRequests = this::syncRequests;
+    private final Runnable mSyncStateWithScheduledReason = this::syncStateWithScheduledReason;
+    private final Runnable mSaveToFile = this::saveToFile;
+
     private PackageWatchdog(Context context) {
         // Needs to be constructed inline
         this(context, new AtomicFile(
@@ -349,7 +353,7 @@
             // Must only run synchronous tasks as this runs on the ShutdownThread and no other
             // thread is guaranteed to run during shutdown.
             if (!mAllObservers.isEmpty()) {
-                mLongTaskHandler.removeCallbacks(this::saveToFileAsync);
+                mLongTaskHandler.removeCallbacks(mSaveToFile);
                 pruneObserversLocked();
                 saveToFile();
                 Slog.i(TAG, "Last write to update package durations");
@@ -424,8 +428,8 @@
      * Serializes and syncs health check requests with the {@link ExplicitHealthCheckController}.
      */
     private void syncRequestsAsync() {
-        mShortTaskHandler.removeCallbacks(this::syncRequests);
-        mShortTaskHandler.post(this::syncRequests);
+        mShortTaskHandler.removeCallbacks(mSyncRequests);
+        mShortTaskHandler.post(mSyncRequests);
     }
 
     /**
@@ -569,14 +573,14 @@
     @GuardedBy("mLock")
     private void scheduleNextSyncStateLocked() {
         long durationMs = getNextStateSyncMillisLocked();
-        mShortTaskHandler.removeCallbacks(this::syncStateWithScheduledReason);
+        mShortTaskHandler.removeCallbacks(mSyncStateWithScheduledReason);
         if (durationMs == Long.MAX_VALUE) {
             Slog.i(TAG, "Cancelling state sync, nothing to sync");
             mUptimeAtLastStateSync = 0;
         } else {
             Slog.i(TAG, "Scheduling next state sync in " + durationMs + "ms");
             mUptimeAtLastStateSync = SystemClock.uptimeMillis();
-            mShortTaskHandler.postDelayed(this::syncStateWithScheduledReason, durationMs);
+            mShortTaskHandler.postDelayed(mSyncStateWithScheduledReason, durationMs);
         }
     }
 
@@ -802,8 +806,8 @@
     }
 
     private void saveToFileAsync() {
-        if (!mLongTaskHandler.hasCallbacks(this::saveToFile)) {
-            mLongTaskHandler.post(this::saveToFile);
+        if (!mLongTaskHandler.hasCallbacks(mSaveToFile)) {
+            mLongTaskHandler.post(mSaveToFile);
         }
     }
 
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 4fab7c1..8367e890 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -140,6 +140,7 @@
 import com.android.internal.util.Preconditions;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.storage.AppFuseBridge;
+import com.android.server.storage.StorageSessionController;
 import com.android.server.wm.ActivityTaskManagerInternal;
 import com.android.server.wm.ActivityTaskManagerInternal.ScreenObserver;
 
@@ -498,6 +499,9 @@
     private final StorageManagerInternalImpl mStorageManagerInternal
             = new StorageManagerInternalImpl();
 
+    // Not guarded by a lock.
+    private final StorageSessionController mStorageSessionController;
+
     class ObbState implements IBinder.DeathRecipient {
         public ObbState(String rawPath, String canonicalPath, int callingUid,
                 IObbActionListener token, int nonce, String volId) {
@@ -647,12 +651,20 @@
                         Slog.i(TAG, "Ignoring mount " + vol.getId() + " due to policy");
                         break;
                     }
-                    mount(vol);
+
+                    // TODO(b/135341433): Remove paranoid logging when FUSE is stable
+                    Slog.i(TAG, "Mounting volume " + vol);
+                    // TODO(b/135341433): Update to use new vold API that gets or mounts fuse fd
+                    // Ensure that we can pass user of a volume to the new API
+                    mStorageSessionController.onVolumeMounted(mCurrentUserId, mount(vol), vol);
+                    Slog.i(TAG, "Mounted volume " + vol);
+
                     break;
                 }
                 case H_VOLUME_UNMOUNT: {
                     final VolumeInfo vol = (VolumeInfo) msg.obj;
                     unmount(vol);
+                    mStorageSessionController.onVolumeUnmounted(mCurrentUserId, vol);
                     break;
                 }
                 case H_VOLUME_BROADCAST: {
@@ -733,6 +745,7 @@
                         }
                     }
                     mVold.onUserRemoved(userId);
+                    mStorageSessionController.onUserRemoved(userId);
                 }
             } catch (Exception e) {
                 Slog.wtf(TAG, e);
@@ -951,7 +964,10 @@
             }
 
             try {
+                // TODO(b/135341433): Remove paranoid logging when FUSE is stable
+                Slog.i(TAG, "Resetting vold");
                 mVold.reset();
+                Slog.i(TAG, "Reset vold");
 
                 // Tell vold about all existing and started users
                 for (UserInfo user : users) {
@@ -976,6 +992,7 @@
         // staging area is ready so it's ready for zygote-forked apps to
         // bind mount against.
         try {
+            mStorageSessionController.onUserStarted(userId);
             mVold.onUserStarted(userId);
             mStoraged.onUserStarted(userId);
         } catch (Exception e) {
@@ -1516,6 +1533,12 @@
         // Add OBB Action Handler to StorageManagerService thread.
         mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
 
+        mStorageSessionController = new StorageSessionController(mContext,
+                userId -> {
+                    Slog.i(TAG, "Storage session ended for user: " + userId + ". Resetting...");
+                    mHandler.obtainMessage(H_RESET).sendToTarget();
+                });
+
         // Initialize the last-fstrim tracking if necessary
         File dataDir = Environment.getDataDirectory();
         File systemDir = new File(dataDir, "system");
@@ -1814,11 +1837,18 @@
         mount(vol);
     }
 
-    private void mount(VolumeInfo vol) {
+    private FileDescriptor mount(VolumeInfo vol) {
         try {
-            mVold.mount(vol.id, vol.mountFlags, vol.mountUserId);
+            // TODO(b/135341433): Now, emulated (and private?) volumes are shared across users
+            // This means the mountUserId on such volumes is USER_NULL. This breaks fuse which
+            // requires a valid user to mount a volume. Create individual volumes per user in vold
+            // and remove this property check
+            int userId = SystemProperties.getBoolean("persist.sys.fuse", false)
+                    ? mCurrentUserId : vol.mountUserId;
+            return mVold.mount(vol.id, vol.mountFlags, userId);
         } catch (Exception e) {
             Slog.wtf(TAG, e);
+            return null;
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 7bc2e6d..8eb5d9b 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2318,9 +2318,8 @@
         return true;
     }
 
+    /** @return {@code true} if the restart is scheduled. */
     private final boolean scheduleServiceRestartLocked(ServiceRecord r, boolean allowCancel) {
-        boolean canceled = false;
-
         if (mAm.mAtmInternal.isShuttingDown()) {
             Slog.w(TAG, "Not scheduling restart of crashed service " + r.shortInstanceName
                     + " - system is shutting down");
@@ -2337,10 +2336,12 @@
 
         final long now = SystemClock.uptimeMillis();
 
+        final String reason;
         if ((r.serviceInfo.applicationInfo.flags
                 &ApplicationInfo.FLAG_PERSISTENT) == 0) {
             long minDuration = mAm.mConstants.SERVICE_RESTART_DURATION;
             long resetTime = mAm.mConstants.SERVICE_RESET_RUN_DURATION;
+            boolean canceled = false;
 
             // Any delivered but not yet finished starts should be put back
             // on the pending list.
@@ -2367,6 +2368,17 @@
                 r.deliveredStarts.clear();
             }
 
+            if (allowCancel) {
+                final boolean shouldStop = r.canStopIfKilled(canceled);
+                if (shouldStop && !r.hasAutoCreateConnections()) {
+                    // Nothing to restart.
+                    return false;
+                }
+                reason = (r.startRequested && !shouldStop) ? "start-requested" : "connection";
+            } else {
+                reason = "always";
+            }
+
             r.totalRestartCount++;
             if (r.restartDelay == 0) {
                 r.restartCount++;
@@ -2418,6 +2430,7 @@
             r.restartCount = 0;
             r.restartDelay = 0;
             r.nextRestartTime = now;
+            reason = "persistent";
         }
 
         if (!mRestartingServices.contains(r)) {
@@ -2432,11 +2445,11 @@
         mAm.mHandler.postAtTime(r.restarter, r.nextRestartTime);
         r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
         Slog.w(TAG, "Scheduling restart of crashed service "
-                + r.shortInstanceName + " in " + r.restartDelay + "ms");
+                + r.shortInstanceName + " in " + r.restartDelay + "ms for " + reason);
         EventLog.writeEvent(EventLogTags.AM_SCHEDULE_SERVICE_RESTART,
                 r.userId, r.shortInstanceName, r.restartDelay);
 
-        return canceled;
+        return true;
     }
 
     final void performServiceRestartLocked(ServiceRecord r) {
@@ -3651,22 +3664,21 @@
                     || !mAm.mUserController.isUserRunning(sr.userId, 0)) {
                 bringDownServiceLocked(sr);
             } else {
-                boolean canceled = scheduleServiceRestartLocked(sr, true);
+                final boolean scheduled = scheduleServiceRestartLocked(sr, true /* allowCancel */);
 
                 // Should the service remain running?  Note that in the
                 // extreme case of so many attempts to deliver a command
                 // that it failed we also will stop it here.
-                if (sr.startRequested && (sr.stopIfKilled || canceled)) {
-                    if (sr.pendingStarts.size() == 0) {
-                        sr.startRequested = false;
-                        if (sr.tracker != null) {
-                            sr.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
-                                    SystemClock.uptimeMillis());
-                        }
-                        if (!sr.hasAutoCreateConnections()) {
-                            // Whoops, no reason to restart!
-                            bringDownServiceLocked(sr);
-                        }
+                if (!scheduled) {
+                    bringDownServiceLocked(sr);
+                } else if (sr.canStopIfKilled(false /* isStartCanceled */)) {
+                    // Update to stopped state because the explicit start is gone. The service is
+                    // scheduled to restart for other reason (e.g. connections) so we don't bring
+                    // down it.
+                    sr.startRequested = false;
+                    if (sr.tracker != null) {
+                        sr.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
+                                SystemClock.uptimeMillis());
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 84f5530..3dc33f8 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4644,7 +4644,7 @@
         }
 
         boolean didSomething = mProcessList.killPackageProcessesLocked(packageName, appId, userId,
-                ProcessList.INVALID_ADJ, callerWillRestart, true /* allowRestart */, doit,
+                ProcessList.INVALID_ADJ, callerWillRestart, false /* allowRestart */, doit,
                 evenPersistent, true /* setRemoved */,
                 packageName == null ? ("stop user " + userId) : ("stop " + packageName));
 
@@ -5268,7 +5268,7 @@
             storageManager.commitChanges();
         } catch (Exception e) {
             PowerManager pm = (PowerManager)
-                     mInjector.getContext().getSystemService(Context.POWER_SERVICE);
+                     mContext.getSystemService(Context.POWER_SERVICE);
             pm.reboot("Checkpoint commit failed");
         }
 
@@ -8285,8 +8285,13 @@
             if (shareDescription != null) {
                 triggerShellBugreport.putExtra(EXTRA_DESCRIPTION, shareDescription);
             }
-            // Send broadcast to shell to trigger bugreport using Bugreport API
-            mContext.sendBroadcast(triggerShellBugreport);
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                // Send broadcast to shell to trigger bugreport using Bugreport API
+                mContext.sendBroadcast(triggerShellBugreport);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
         } else {
             SystemProperties.set("dumpstate.options", type);
             SystemProperties.set("ctl.start", "bugreport");
@@ -9154,10 +9159,10 @@
                 }
                 t.traceEnd();
             }
-            // Automotive will re-start system user as background (so its unlocked), then start a
-            // full user as foreground. Hence, we need to skip some steps that would otherwise be
-            // done twice.
-            // TODO(b/138956267): this workdound shouldn't be necessary once we move the
+
+            // On Automotive, at this point the system user has already been started and unlocked,
+            // and some of the tasks we do here have already been done. So skip those in that case.
+            // TODO(b/132262830): this workdound shouldn't be necessary once we move the
             // headless-user start logic to UserManager-land
             final boolean bootingSystemUser = currentUserId == UserHandle.USER_SYSTEM;
 
@@ -13919,9 +13924,9 @@
         // Remove published content providers.
         for (int i = app.pubProviders.size() - 1; i >= 0; i--) {
             ContentProviderRecord cpr = app.pubProviders.valueAt(i);
-            final boolean always = app.bad || !allowRestart;
-            boolean inLaunching = removeDyingProviderLocked(app, cpr, always);
-            if ((inLaunching || always) && cpr.hasConnectionOrHandle()) {
+            final boolean alwaysRemove = app.bad || !allowRestart;
+            final boolean inLaunching = removeDyingProviderLocked(app, cpr, alwaysRemove);
+            if (!alwaysRemove && inLaunching && cpr.hasConnectionOrHandle()) {
                 // We left the provider in the launching list, need to
                 // restart it.
                 restart = true;
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 8619ad5..8c038aa 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -19,9 +19,7 @@
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 
-import android.app.INotificationManager;
 import android.app.Notification;
-import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
@@ -33,7 +31,6 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.IBinder;
-import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -623,6 +620,14 @@
         }
     }
 
+    /**
+     * @return {@code true} if the killed service which was started by {@link Context#startService}
+     *         has no reason to start again. Note this condition doesn't consider the bindings.
+     */
+    boolean canStopIfKilled(boolean isStartCanceled) {
+        return startRequested && (stopIfKilled || isStartCanceled) && pendingStarts.isEmpty();
+    }
+
     void updateHasBindingWhitelistingBgActivityStarts() {
         boolean hasWhitelistingBinding = false;
         for (int conni = connections.size() - 1; conni >= 0; conni--) {
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 2b4cc3c..5fe72dd 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -1755,9 +1755,10 @@
         for (int i = 0; i < startedUsers.size(); i++) {
             UserState uss = startedUsers.valueAt(i);
             if (systemUserFinishedBooting && uss.mHandle.isSystem()) {
-                // Automotive will re-start system user as background, which in turn will call
-                // finishUserboot(). Hence, we need to check it here to avoid calling it twice.
-                // TODO(b/138956267): this workdound shouldn't be necessary once we move the
+                // On Automotive, at this point the system user has already been started and
+                // unlocked, and some of the tasks we do here have already been done. So skip those
+                // in that case.
+                // TODO(b/132262830): this workdound shouldn't be necessary once we move the
                 // headless-user start logic to UserManager-land
                 Slog.d(TAG, "sendBootCompleted(): skipping on non-current system user");
                 continue;
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 6d6a148..cc8e3f0 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -2973,28 +2973,49 @@
                 out.startTag(null, "app-ops");
                 out.attribute(null, "v", String.valueOf(CURRENT_VERSION));
 
+                SparseArray<SparseIntArray> uidStatesClone;
                 synchronized (this) {
+                    uidStatesClone = new SparseArray<>(mUidStates.size());
+
                     final int uidStateCount = mUidStates.size();
-                    for (int i = 0; i < uidStateCount; i++) {
-                        UidState uidState = mUidStates.valueAt(i);
-                        if (uidState.opModes != null && uidState.opModes.size() > 0) {
-                            out.startTag(null, "uid");
-                            out.attribute(null, "n", Integer.toString(uidState.uid));
-                            SparseIntArray uidOpModes = uidState.opModes;
-                            final int opCount = uidOpModes.size();
-                            for (int j = 0; j < opCount; j++) {
-                                final int op = uidOpModes.keyAt(j);
-                                final int mode = uidOpModes.valueAt(j);
-                                out.startTag(null, "op");
-                                out.attribute(null, "n", Integer.toString(op));
-                                out.attribute(null, "m", Integer.toString(mode));
-                                out.endTag(null, "op");
+                    for (int uidStateNum = 0; uidStateNum < uidStateCount; uidStateNum++) {
+                        UidState uidState = mUidStates.valueAt(uidStateNum);
+                        int uid = mUidStates.keyAt(uidStateNum);
+
+                        SparseIntArray opModes = uidState.opModes;
+                        if (opModes != null && opModes.size() > 0) {
+                            uidStatesClone.put(uid, new SparseIntArray(opModes.size()));
+
+                            final int opCount = opModes.size();
+                            for (int opCountNum = 0; opCountNum < opCount; opCountNum++) {
+                                uidStatesClone.get(uid).put(
+                                        opModes.keyAt(opCountNum),
+                                        opModes.valueAt(opCountNum));
                             }
-                            out.endTag(null, "uid");
                         }
                     }
                 }
 
+                final int uidStateCount = uidStatesClone.size();
+                for (int uidStateNum = 0; uidStateNum < uidStateCount; uidStateNum++) {
+                    SparseIntArray opModes = uidStatesClone.valueAt(uidStateNum);
+                    if (opModes != null && opModes.size() > 0) {
+                        out.startTag(null, "uid");
+                        out.attribute(null, "n",
+                                Integer.toString(uidStatesClone.keyAt(uidStateNum)));
+                        final int opCount = opModes.size();
+                        for (int opCountNum = 0; opCountNum < opCount; opCountNum++) {
+                            final int op = opModes.keyAt(opCountNum);
+                            final int mode = opModes.valueAt(opCountNum);
+                            out.startTag(null, "op");
+                            out.attribute(null, "n", Integer.toString(op));
+                            out.attribute(null, "m", Integer.toString(mode));
+                            out.endTag(null, "op");
+                        }
+                        out.endTag(null, "uid");
+                    }
+                }
+
                 if (allOps != null) {
                     String lastPkg = null;
                     for (int i=0; i<allOps.size(); i++) {
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 24e6a75..4af3627 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -514,7 +514,6 @@
         }
 
         public boolean getFaceEnabledForApps(int userId) {
-            Slog.e(TAG, "getFaceEnabledForApps: " + userId, new Exception());
             if (!mFaceEnabledForApps.containsKey(userId)) {
                 onChange(true /* selfChange */, FACE_UNLOCK_APP_ENABLED, userId);
             }
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index 044e417..027e2fb 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -47,11 +47,10 @@
 public final class CompatConfig {
 
     private static final String TAG = "CompatConfig";
-    private static final String CONFIG_FILE_SUFFIX = "platform_compat_config.xml";
 
     private static final CompatConfig sInstance = new CompatConfig().initConfigFromLib(
             Environment.buildPath(
-                    Environment.getRootDirectory(), "etc", "sysconfig"));
+                    Environment.getRootDirectory(), "etc", "compatconfig"));
 
     @GuardedBy("mChanges")
     private final LongSparseArray<CompatChange> mChanges = new LongSparseArray<>();
@@ -212,10 +211,9 @@
             return this;
         }
         for (File f : libraryDir.listFiles()) {
+            Slog.d(TAG, "Found a config file: " + f.getPath());
             //TODO(b/138222363): Handle duplicate ids across config files.
-            if (f.getPath().endsWith(CONFIG_FILE_SUFFIX)) {
-                readConfig(f);
-            }
+            readConfig(f);
         }
         return this;
     }
@@ -223,7 +221,7 @@
     private void readConfig(File configFile) {
         try (InputStream in = new BufferedInputStream(new FileInputStream(configFile))) {
             for (Change change : XmlParser.read(in).getCompatChange()) {
-                Slog.w(TAG, "Adding: " + change.toString());
+                Slog.d(TAG, "Adding: " + change.toString());
                 addChange(new CompatChange(change));
             }
         } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
diff --git a/services/core/java/com/android/server/connectivity/DataConnectionStats.java b/services/core/java/com/android/server/connectivity/DataConnectionStats.java
index 4990ea1..27f11ff 100644
--- a/services/core/java/com/android/server/connectivity/DataConnectionStats.java
+++ b/services/core/java/com/android/server/connectivity/DataConnectionStats.java
@@ -21,6 +21,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.ConnectivityManager;
+import android.os.Handler;
+import android.os.Looper;
 import android.os.RemoteException;
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
@@ -39,15 +41,19 @@
 
     private final Context mContext;
     private final IBatteryStats mBatteryStats;
+    private final Handler mListenerHandler;
+    private final PhoneStateListener mPhoneStateListener;
 
     private IccCardConstants.State mSimState = IccCardConstants.State.READY;
     private SignalStrength mSignalStrength;
     private ServiceState mServiceState;
     private int mDataState = TelephonyManager.DATA_DISCONNECTED;
 
-    public DataConnectionStats(Context context) {
+    public DataConnectionStats(Context context, Handler listenerHandler) {
         mContext = context;
         mBatteryStats = BatteryStatsService.getService();
+        mListenerHandler = listenerHandler;
+        mPhoneStateListener = new PhoneStateListenerImpl(listenerHandler.getLooper());
     }
 
     public void startMonitoring() {
@@ -63,7 +69,7 @@
         filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
         filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
         filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
-        mContext.registerReceiver(this, filter);
+        mContext.registerReceiver(this, filter, null /* broadcastPermission */, mListenerHandler);
     }
 
     @Override
@@ -129,7 +135,11 @@
                 && mServiceState.getState() != ServiceState.STATE_POWER_OFF;
     }
 
-    private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+    private class PhoneStateListenerImpl extends PhoneStateListener {
+        PhoneStateListenerImpl(Looper looper) {
+            super(looper);
+        }
+
         @Override
         public void onSignalStrengthsChanged(SignalStrength signalStrength) {
             mSignalStrength = signalStrength;
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 86d1212..5fd5c4b 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -455,7 +455,20 @@
 
             @Override
             public void onServiceConnected(int profile, BluetoothProfile proxy) {
-                ((BluetoothPan) proxy).setBluetoothTethering(enable);
+                // 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)
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 4d5dc6a..2b849d6 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -297,6 +297,11 @@
             mHdmiControlBroadcastReceiver = new HdmiControlBroadcastReceiver();
 
     @Nullable
+    // Save callback when the device is still under logcial address allocation
+    // Invoke once new local device is ready.
+    private IHdmiControlCallback mDisplayStatusCallback = null;
+
+    @Nullable
     private HdmiCecController mCecController;
 
     // HDMI port information. Stored in the unmodifiable list to keep the static information
@@ -763,6 +768,11 @@
                     // Address allocation completed for all devices. Notify each device.
                     if (allocatingDevices.size() == ++finished[0]) {
                         mAddressAllocated = true;
+                        // Reinvoke the saved display status callback once the local device is ready.
+                        if (mDisplayStatusCallback != null) {
+                            queryDisplayStatus(mDisplayStatusCallback);
+                            mDisplayStatusCallback = null;
+                        }
                         if (initiatedBy != INITIATED_BY_HOTPLUG) {
                             // In case of the hotplug we don't call onInitializeCecComplete()
                             // since we reallocate the logical address only.
@@ -2192,6 +2202,13 @@
     @ServiceThreadOnly
     private void queryDisplayStatus(final IHdmiControlCallback callback) {
         assertRunOnServiceThread();
+        if (!mAddressAllocated) {
+            mDisplayStatusCallback = callback;
+            Slog.d(TAG, "Local device is under address allocation. "
+                        + "Queue display callback for later process.");
+            return;
+        }
+
         HdmiCecLocalDevicePlayback source = playback();
         if (source == null) {
             Slog.w(TAG, "Local playback device not available");
diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index 9782f30..d71ffb7 100644
--- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -48,6 +48,7 @@
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -79,7 +80,7 @@
         S extends AbstractPerUserSystemService<S, M>> extends SystemService {
 
     /** On a package update, does not refresh the per-user service in the cache. */
-    public static final int PACKAGE_UPDATE_POLICY_NO_REFRESH = 0;
+    public static final int PACKAGE_UPDATE_POLICY_NO_REFRESH = 0x00000001;
 
     /**
      * On a package update, removes any existing per-user services in the cache.
@@ -87,20 +88,40 @@
      * <p>This does not immediately recreate these services. It is assumed they will be recreated
      * for the next user request.
      */
-    public static final int PACKAGE_UPDATE_POLICY_REFRESH_LAZY = 1;
+    public static final int PACKAGE_UPDATE_POLICY_REFRESH_LAZY = 0x00000002;
 
     /**
      * On a package update, removes and recreates any existing per-user services in the cache.
      */
-    public static final int PACKAGE_UPDATE_POLICY_REFRESH_EAGER = 2;
+    public static final int PACKAGE_UPDATE_POLICY_REFRESH_EAGER = 0x00000004;
 
-    @IntDef(flag = true, prefix = { "PACKAGE_UPDATE_POLICY_" }, value = {
+    /** On a package restart, does not refresh the per-user service in the cache. */
+    public static final int PACKAGE_RESTART_POLICY_NO_REFRESH = 0x00000010;
+
+    /**
+     * On a package restart, removes any existing per-user services in the cache.
+     *
+     * <p>This does not immediately recreate these services. It is assumed they will be recreated
+     * for the next user request.
+     */
+    public static final int PACKAGE_RESTART_POLICY_REFRESH_LAZY = 0x00000020;
+
+    /**
+     * On a package restart, removes and recreates any existing per-user services in the cache.
+     */
+    public static final int PACKAGE_RESTART_POLICY_REFRESH_EAGER = 0x00000040;
+
+    @IntDef(flag = true, prefix = { "PACKAGE_" }, value = {
             PACKAGE_UPDATE_POLICY_NO_REFRESH,
             PACKAGE_UPDATE_POLICY_REFRESH_LAZY,
-            PACKAGE_UPDATE_POLICY_REFRESH_EAGER
+            PACKAGE_UPDATE_POLICY_REFRESH_EAGER,
+            PACKAGE_RESTART_POLICY_NO_REFRESH,
+            PACKAGE_RESTART_POLICY_REFRESH_LAZY,
+            PACKAGE_RESTART_POLICY_REFRESH_EAGER
     })
+
     @Retention(RetentionPolicy.SOURCE)
-    public @interface PackageUpdatePolicy {}
+    public @interface ServicePackagePolicyFlags {}
 
     /**
      * Log tag
@@ -153,12 +174,10 @@
     private final SparseArray<S> mServicesCache = new SparseArray<>();
 
     /**
-     * Whether the per-user service should be removed from the cache when its apk is updated.
-     *
-     * <p>One of {@link #PACKAGE_UPDATE_POLICY_NO_REFRESH},
-     * {@link #PACKAGE_UPDATE_POLICY_REFRESH_LAZY} or {@link #PACKAGE_UPDATE_POLICY_REFRESH_EAGER}.
+     * Value that determines whether the per-user service should be removed from the cache when its
+     * apk is updated or restarted.
      */
-    private final @PackageUpdatePolicy int mPackageUpdatePolicy;
+    private final @ServicePackagePolicyFlags int mServicePackagePolicyFlags;
 
     /**
      * Name of the service packages whose APK are being updated, keyed by user id.
@@ -167,6 +186,12 @@
     private SparseArray<String> mUpdatingPackageNames;
 
     /**
+     * Lazy-loadable reference to {@link UserManagerInternal}.
+     */
+    @Nullable
+    private UserManagerInternal mUm;
+
+    /**
      * Default constructor.
      *
      * <p>When using this constructor, the {@link AbstractPerUserSystemService} is removed from
@@ -184,11 +209,11 @@
             @Nullable ServiceNameResolver serviceNameResolver,
             @Nullable String disallowProperty) {
         this(context, serviceNameResolver, disallowProperty,
-                /*packageUpdatePolicy=*/ PACKAGE_UPDATE_POLICY_REFRESH_LAZY);
+                PACKAGE_UPDATE_POLICY_REFRESH_LAZY | PACKAGE_RESTART_POLICY_REFRESH_LAZY);
     }
 
     /**
-     * Full constructor.
+     * Full Constructor.
      *
      * @param context system context.
      * @param serviceNameResolver resolver for
@@ -197,19 +222,32 @@
      * @param disallowProperty when not {@code null}, defines a {@link UserManager} restriction that
      *        disables the service. <b>NOTE: </b> you'll also need to add it to
      *        {@code UserRestrictionsUtils.USER_RESTRICTIONS}.
-     * @param packageUpdatePolicy when {@link #PACKAGE_UPDATE_POLICY_REFRESH_LAZY}, the
-     *        {@link AbstractPerUserSystemService} is removed from the cache when the service
-     *        package is updated; when {@link #PACKAGE_UPDATE_POLICY_REFRESH_EAGER}, the
-     *        {@link AbstractPerUserSystemService} is removed from the cache and immediately
-     *        re-added when the service package is updated; when
-     *        {@link #PACKAGE_UPDATE_POLICY_NO_REFRESH}, the service is untouched during the update.
+     * @param servicePackagePolicyFlags a combination of
+     *        {@link #PACKAGE_UPDATE_POLICY_NO_REFRESH},
+     *        {@link #PACKAGE_UPDATE_POLICY_REFRESH_LAZY},
+     *        {@link #PACKAGE_UPDATE_POLICY_REFRESH_EAGER},
+     *        {@link #PACKAGE_RESTART_POLICY_NO_REFRESH},
+     *        {@link #PACKAGE_RESTART_POLICY_REFRESH_LAZY} or
+     *        {@link #PACKAGE_RESTART_POLICY_REFRESH_EAGER}
      */
     protected AbstractMasterSystemService(@NonNull Context context,
-            @Nullable ServiceNameResolver serviceNameResolver,
-            @Nullable String disallowProperty, @PackageUpdatePolicy int packageUpdatePolicy) {
+            @Nullable ServiceNameResolver serviceNameResolver, @Nullable String disallowProperty,
+            @ServicePackagePolicyFlags int servicePackagePolicyFlags) {
         super(context);
 
-        mPackageUpdatePolicy = packageUpdatePolicy;
+        final int updatePolicyMask = PACKAGE_UPDATE_POLICY_NO_REFRESH
+                | PACKAGE_UPDATE_POLICY_REFRESH_LAZY | PACKAGE_UPDATE_POLICY_REFRESH_EAGER;
+        if ((servicePackagePolicyFlags & updatePolicyMask) == 0) {
+            // If the package update policy is not set, add the default flag
+            servicePackagePolicyFlags |= PACKAGE_UPDATE_POLICY_REFRESH_LAZY;
+        }
+        final int restartPolicyMask = PACKAGE_RESTART_POLICY_NO_REFRESH
+                | PACKAGE_RESTART_POLICY_REFRESH_LAZY | PACKAGE_RESTART_POLICY_REFRESH_EAGER;
+        if ((servicePackagePolicyFlags & restartPolicyMask) == 0) {
+            // If the package restart policy is not set, add the default flag
+            servicePackagePolicyFlags |= PACKAGE_RESTART_POLICY_REFRESH_LAZY;
+        }
+        mServicePackagePolicyFlags = servicePackagePolicyFlags;
 
         mServiceNameResolver = serviceNameResolver;
         if (mServiceNameResolver != null) {
@@ -222,9 +260,8 @@
         } else {
             mDisabledByUserRestriction = new SparseBooleanArray();
             // Hookup with UserManager to disable service when necessary.
-            final UserManager um = context.getSystemService(UserManager.class);
-            final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
-            final List<UserInfo> users = um.getUsers();
+            final UserManagerInternal umi = getUserManagerInternal();
+            final List<UserInfo> users = getSupportedUsers();
             for (int i = 0; i < users.size(); i++) {
                 final int userId = users.get(i).id;
                 final boolean disabled = umi.getUserRestriction(userId, disallowProperty);
@@ -606,6 +643,20 @@
     }
 
     /**
+     * Called after the package data that provides the service for the given user is cleared.
+     */
+    protected void onServicePackageDataClearedLocked(@UserIdInt int userId) {
+        if (verbose) Slog.v(mTag, "onServicePackageDataCleared(" + userId + ")");
+    }
+
+    /**
+     * Called after the package that provides the service for the given user is restarted.
+     */
+    protected void onServicePackageRestartedLocked(@UserIdInt int userId) {
+        if (verbose) Slog.v(mTag, "onServicePackageRestarted(" + userId + ")");
+    }
+
+    /**
      * Called after the service is removed from the cache.
      */
     @SuppressWarnings("unused")
@@ -649,6 +700,36 @@
     }
 
     /**
+     * Gets a cached reference to {@link UserManagerInternal}.
+     */
+    @NonNull
+    protected UserManagerInternal getUserManagerInternal() {
+        if (mUm == null) {
+            if (verbose) Slog.v(mTag, "lazy-loading UserManagerInternal");
+            mUm = LocalServices.getService(UserManagerInternal.class);
+        }
+        return mUm;
+    }
+
+    /**
+     * Gets a list of all supported users (i.e., those that pass the {@link #isSupported(UserInfo)}
+     * check).
+     */
+    @NonNull
+    protected List<UserInfo> getSupportedUsers() {
+        final UserInfo[] allUsers = getUserManagerInternal().getUserInfos();
+        final int size = allUsers.length;
+        final List<UserInfo> supportedUsers = new ArrayList<>(size);
+        for (int i = 0; i < size; i++) {
+            final UserInfo userInfo = allUsers[i];
+            if (isSupported(userInfo)) {
+                supportedUsers.add(userInfo);
+            }
+        }
+        return supportedUsers;
+    }
+
+    /**
      * Asserts that the given package name is owned by the UID making this call.
      *
      * @throws SecurityException when it's not...
@@ -677,15 +758,14 @@
             final int size = mServicesCache.size();
             pw.print(prefix); pw.print("Debug: "); pw.print(realDebug);
             pw.print(" Verbose: "); pw.println(realVerbose);
-            pw.print("Refresh on package update: "); pw.println(mPackageUpdatePolicy);
+            pw.print("Package policy flags: "); pw.println(mServicePackagePolicyFlags);
             if (mUpdatingPackageNames != null) {
                 pw.print("Packages being updated: "); pw.println(mUpdatingPackageNames);
             }
             if (mServiceNameResolver != null) {
                 pw.print(prefix); pw.print("Name resolver: ");
                 mServiceNameResolver.dumpShort(pw); pw.println();
-                final UserManager um = getContext().getSystemService(UserManager.class);
-                final List<UserInfo> users = um.getUsers();
+                final List<UserInfo> users = getSupportedUsers();
                 for (int i = 0; i < users.size(); i++) {
                     final int userId = users.get(i).id;
                     pw.print(prefix2); pw.print(userId); pw.print(": ");
@@ -733,7 +813,12 @@
                     }
                     mUpdatingPackageNames.put(userId, packageName);
                     onServicePackageUpdatingLocked(userId);
-                    if (mPackageUpdatePolicy != PACKAGE_UPDATE_POLICY_NO_REFRESH) {
+                    if ((mServicePackagePolicyFlags & PACKAGE_UPDATE_POLICY_NO_REFRESH) != 0) {
+                        if (debug) {
+                            Slog.d(mTag, "Holding service for user " + userId + " while package "
+                                    + activePackageName + " is being updated");
+                        }
+                    } else {
                         if (debug) {
                             Slog.d(mTag, "Removing service for user " + userId
                                     + " because package " + activePackageName
@@ -741,18 +826,14 @@
                         }
                         removeCachedServiceLocked(userId);
 
-                        if (mPackageUpdatePolicy == PACKAGE_UPDATE_POLICY_REFRESH_EAGER) {
+                        if ((mServicePackagePolicyFlags & PACKAGE_UPDATE_POLICY_REFRESH_EAGER)
+                                != 0) {
                             if (debug) {
                                 Slog.d(mTag, "Eagerly recreating service for user "
                                         + userId);
                             }
                             getServiceForUserLocked(userId);
                         }
-                    } else {
-                        if (debug) {
-                            Slog.d(mTag, "Holding service for user " + userId + " while package "
-                                    + activePackageName + " is being updated");
-                        }
                     }
                 }
             }
@@ -804,7 +885,13 @@
                             if (!doit) {
                                 return true;
                             }
-                            removeCachedServiceLocked(getChangingUserId());
+                            final String action = intent.getAction();
+                            final int userId = getChangingUserId();
+                            if (Intent.ACTION_PACKAGE_RESTARTED.equals(action)) {
+                                handleActiveServiceRestartedLocked(activePackageName, userId);
+                            } else {
+                                removeCachedServiceLocked(userId);
+                            }
                         } else {
                             handlePackageUpdateLocked(pkg);
                         }
@@ -813,6 +900,23 @@
                 return false;
             }
 
+            @Override
+            public void onPackageDataCleared(String packageName, int uid) {
+                if (verbose) Slog.v(mTag, "onPackageDataCleared(): " + packageName);
+                final int userId = getChangingUserId();
+                synchronized (mLock) {
+                    final S service = peekServiceForUserLocked(userId);
+                    if (service != null) {
+                        final ComponentName componentName = service.getServiceComponentName();
+                        if (componentName != null) {
+                            if (packageName.equals(componentName.getPackageName())) {
+                                onServicePackageDataClearedLocked(userId);
+                            }
+                        }
+                    }
+                }
+            }
+
             private void handleActiveServiceRemoved(@UserIdInt int userId) {
                 synchronized (mLock) {
                     removeCachedServiceLocked(userId);
@@ -824,6 +928,31 @@
                 }
             }
 
+            private void handleActiveServiceRestartedLocked(String activePackageName,
+                    @UserIdInt int userId) {
+                if ((mServicePackagePolicyFlags & PACKAGE_RESTART_POLICY_NO_REFRESH) != 0) {
+                    if (debug) {
+                        Slog.d(mTag, "Holding service for user " + userId + " while package "
+                                + activePackageName + " is being restarted");
+                    }
+                } else {
+                    if (debug) {
+                        Slog.d(mTag, "Removing service for user " + userId
+                                + " because package " + activePackageName
+                                + " is being restarted");
+                    }
+                    removeCachedServiceLocked(userId);
+
+                    if ((mServicePackagePolicyFlags & PACKAGE_RESTART_POLICY_REFRESH_EAGER) != 0) {
+                        if (debug) {
+                            Slog.d(mTag, "Eagerly recreating service for user " + userId);
+                        }
+                        getServiceForUserLocked(userId);
+                    }
+                }
+                onServicePackageRestartedLocked(userId);
+            }
+
             private String getActiveServicePackageNameLocked() {
                 final int userId = getChangingUserId();
                 final S service = peekServiceForUserLocked(userId);
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index f38f2f9..ccc0d4b 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -217,6 +217,11 @@
     private final RecoverableKeyStoreManager mRecoverableKeyStoreManager;
 
     private boolean mFirstCallToVold;
+    // Current password metric for all users on the device. Updated when user unlocks
+    // the device or changes password. Removed when user is stopped.
+    @GuardedBy("this")
+    final SparseArray<PasswordMetrics> mUserPasswordMetrics = new SparseArray<>();
+
     protected IGateKeeperService mGateKeeperService;
     protected IAuthSecret mAuthSecretService;
 
@@ -424,6 +429,13 @@
             return (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         }
 
+        /**
+         * Return the {@link DevicePolicyManager} object.
+         *
+         * Since LockSettingsService is considered a lower-level component than DevicePolicyManager,
+         * do NOT hold any lock in this class while calling into DevicePolicyManager to prevent
+         * the risk of deadlock.
+         */
         public DevicePolicyManager getDevicePolicyManager() {
             return (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
         }
@@ -593,6 +605,9 @@
         // the device.
         int strongAuthRequired = LockPatternUtils.StrongAuthTracker.getDefaultFlags(mContext);
         requireStrongAuth(strongAuthRequired, userId);
+        synchronized (this) {
+            mUserPasswordMetrics.remove(userId);
+        }
     }
 
     public void onStartUser(final int userId) {
@@ -1501,7 +1516,7 @@
             setKeystorePassword(null, userId);
             fixateNewestUserKeyAuth(userId);
             synchronizeUnifiedWorkChallengeForProfiles(userId, null);
-            notifyActivePasswordMetricsAvailable(CREDENTIAL_TYPE_NONE, null, userId);
+            setUserPasswordMetrics(CREDENTIAL_TYPE_NONE, null, userId);
             sendCredentialsOnChangeIfRequired(
                     credentialType, credential, userId, isLockTiedToParent);
             return;
@@ -1946,7 +1961,7 @@
                     Log.w(TAG, "progressCallback throws exception", e);
                 }
             }
-            notifyActivePasswordMetricsAvailable(storedHash.type, credential, userId);
+            setUserPasswordMetrics(storedHash.type, credential, userId);
             unlockKeystore(credential, userId);
 
             Slog.i(TAG, "Unlocking user " + userId + " with token length "
@@ -1988,32 +2003,40 @@
     }
 
     /**
-     * Call this method to notify DPMS regarding the latest password metric. This should be called
-     * when the user is authenticating or when a new password is being set.
+     * Keep track of the given user's latest password metric. This should be called
+     * when the user is authenticating or when a new password is being set. In comparison,
+     * {@link #notifyPasswordChanged} only needs to be called when the user changes the password.
      */
-    private void notifyActivePasswordMetricsAvailable(
-            @CredentialType int credentialType, byte[] password, @UserIdInt int userId) {
-        final PasswordMetrics metrics =
-                PasswordMetrics.computeForCredential(credentialType, password);
+    private void setUserPasswordMetrics(@CredentialType int credentialType, byte[] password,
+            @UserIdInt int userHandle) {
+        synchronized (this) {
+            mUserPasswordMetrics.put(userHandle,
+                    PasswordMetrics.computeForCredential(credentialType, password));
+        }
+    }
 
-        // Asynchronous to avoid dead lock
-        mHandler.post(() -> {
-            final DevicePolicyManager dpm = (DevicePolicyManager)
-                    mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
-            dpm.setActivePasswordState(metrics, userId);
-        });
+    @VisibleForTesting
+    PasswordMetrics getUserPasswordMetrics(int userHandle) {
+        if (!isUserSecure(userHandle)) {
+            // for users without password, mUserPasswordMetrics might not be initialized
+            // since the user never unlock the device manually. In this case, always
+            // return a default metrics object. This is to distinguish this case from
+            // the case where during boot user password is unknown yet (returning null here)
+            return new PasswordMetrics();
+        }
+        synchronized (this) {
+            return mUserPasswordMetrics.get(userHandle);
+        }
     }
 
     /**
-     * Call after {@link #notifyActivePasswordMetricsAvailable} so metrics are updated before
+     * Call after {@link #setUserPasswordMetrics} so metrics are updated before
      * reporting the password changed.
      */
     private void notifyPasswordChanged(@UserIdInt int userId) {
         // Same handler as notifyActivePasswordMetricsAvailable to ensure correct ordering
         mHandler.post(() -> {
-            DevicePolicyManager dpm = (DevicePolicyManager)
-                    mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
-            dpm.reportPasswordChanged(userId);
+            mInjector.getDevicePolicyManager().reportPasswordChanged(userId);
             LocalServices.getService(WindowManagerInternal.class).reportPasswordChanged(userId);
         });
     }
@@ -2582,7 +2605,7 @@
         }
 
         if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
-            notifyActivePasswordMetricsAvailable(credentialType, userCredential, userId);
+            setUserPasswordMetrics(credentialType, userCredential, userId);
             unlockKeystore(authResult.authToken.deriveKeyStorePassword(), userId);
 
             // Do resetLockout / revokeChallenge when all profiles are unlocked
@@ -2676,7 +2699,7 @@
         setSyntheticPasswordHandleLocked(newHandle, userId);
         synchronizeUnifiedWorkChallengeForProfiles(userId, profilePasswords);
 
-        notifyActivePasswordMetricsAvailable(credentialType, credential, userId);
+        setUserPasswordMetrics(credentialType, credential, userId);
 
         if (profilePasswords != null) {
             for (Map.Entry<Integer, byte[]> entry : profilePasswords.entrySet()) {
@@ -2982,6 +3005,8 @@
             pw.println("hasPassword: " + havePassword(userId));
             pw.println("hasPattern: " + havePattern(userId)); // print raw credential type instead?
             pw.println("SeparateChallenge: " + getSeparateProfileChallengeEnabled(userId));
+            pw.println(String.format("metrics: %s",
+                    getUserPasswordMetrics(userId) != null ? "known" : "unknown"));
             pw.decreaseIndent();
         }
         pw.println();
@@ -3158,5 +3183,23 @@
         public boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) {
             return LockSettingsService.this.unlockUserWithToken(tokenHandle, token, userId);
         }
+
+        @Override
+        public PasswordMetrics getUserPasswordMetrics(int userHandle) {
+            long identity = Binder.clearCallingIdentity();
+            try {
+                if (isManagedProfileWithUnifiedLock(userHandle)) {
+                    // A managed profile with unified challenge is supposed to be protected by the
+                    // parent lockscreen, so asking for its password metrics is not really useful,
+                    // as this method would just return the metrics of the random profile password
+                    Slog.w(TAG, "Querying password metrics for unified challenge profile: "
+                            + userHandle);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+            return LockSettingsService.this.getUserPasswordMetrics(userHandle);
+        }
+
     }
 }
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index 3f15b38..77fbe41 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -19,6 +19,8 @@
 import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
 import static android.provider.Settings.ACTION_VPN_SETTINGS;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -32,7 +34,7 @@
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkInfo.State;
-import android.os.INetworkManagementService;
+import android.os.Handler;
 import android.security.Credentials;
 import android.security.KeyStore;
 import android.text.TextUtils;
@@ -63,22 +65,19 @@
 
     private static final String ACTION_LOCKDOWN_RESET = "com.android.server.action.LOCKDOWN_RESET";
 
-    private static final int ROOT_UID = 0;
+    @NonNull private final Context mContext;
+    @NonNull private final ConnectivityService mConnService;
+    @NonNull private final Handler mHandler;
+    @NonNull private final Vpn mVpn;
+    @NonNull private final VpnProfile mProfile;
 
-    private final Context mContext;
-    private final INetworkManagementService mNetService;
-    private final ConnectivityService mConnService;
-    private final Vpn mVpn;
-    private final VpnProfile mProfile;
+    @NonNull private final Object mStateLock = new Object();
 
-    private final Object mStateLock = new Object();
+    @NonNull private final PendingIntent mConfigIntent;
+    @NonNull private final PendingIntent mResetIntent;
 
-    private final PendingIntent mConfigIntent;
-    private final PendingIntent mResetIntent;
-
+    @Nullable
     private String mAcceptedEgressIface;
-    private String mAcceptedIface;
-    private List<LinkAddress> mAcceptedSourceAddr;
 
     private int mErrorCount;
 
@@ -86,11 +85,14 @@
         return KeyStore.getInstance().contains(Credentials.LOCKDOWN_VPN);
     }
 
-    public LockdownVpnTracker(Context context, INetworkManagementService netService,
-            ConnectivityService connService, Vpn vpn, VpnProfile profile) {
+    public LockdownVpnTracker(@NonNull Context context,
+            @NonNull ConnectivityService connService,
+            @NonNull Handler handler,
+            @NonNull Vpn vpn,
+            @NonNull VpnProfile profile) {
         mContext = Preconditions.checkNotNull(context);
-        mNetService = Preconditions.checkNotNull(netService);
         mConnService = Preconditions.checkNotNull(connService);
+        mHandler = Preconditions.checkNotNull(handler);
         mVpn = Preconditions.checkNotNull(vpn);
         mProfile = Preconditions.checkNotNull(profile);
 
@@ -176,11 +178,6 @@
             final String iface = vpnConfig.interfaze;
             final List<LinkAddress> sourceAddrs = vpnConfig.addresses;
 
-            if (TextUtils.equals(iface, mAcceptedIface)
-                  && sourceAddrs.equals(mAcceptedSourceAddr)) {
-                return;
-            }
-
             Slog.d(TAG, "VPN connected using iface=" + iface +
                     ", sourceAddr=" + sourceAddrs.toString());
             EventLogTags.writeLockdownVpnConnected(egressType);
@@ -205,7 +202,7 @@
         mVpn.setLockdown(true);
 
         final IntentFilter resetFilter = new IntentFilter(ACTION_LOCKDOWN_RESET);
-        mContext.registerReceiver(mResetReceiver, resetFilter, CONNECTIVITY_INTERNAL, null);
+        mContext.registerReceiver(mResetReceiver, resetFilter, CONNECTIVITY_INTERNAL, mHandler);
 
         handleStateChangedLocked();
     }
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index b4a8099..976a0c6 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -217,6 +217,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.notification.SystemNotificationChannels;
+import com.android.internal.os.SomeArgs;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.ConcurrentUtils;
@@ -3281,7 +3282,7 @@
 
     @Override
     public void setSubscriptionOverride(int subId, int overrideMask, int overrideValue,
-            long timeoutMillis, String callingPackage) {
+            long networkTypeMask, long timeoutMillis, String callingPackage) {
         enforceSubscriptionPlanAccess(subId, Binder.getCallingUid(), callingPackage);
 
         // We can only override when carrier told us about plans
@@ -3299,11 +3300,16 @@
         final boolean overrideEnabled = Settings.Global.getInt(mContext.getContentResolver(),
                 NETPOLICY_OVERRIDE_ENABLED, 1) != 0;
         if (overrideEnabled || overrideValue == 0) {
-            mHandler.sendMessage(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE,
-                    overrideMask, overrideValue, subId));
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = subId;
+            args.arg2 = overrideMask;
+            args.arg3 = overrideValue;
+            args.arg4 = networkTypeMask;
+            mHandler.sendMessage(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE, args));
             if (timeoutMillis > 0) {
-                mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE,
-                        overrideMask, 0, subId), timeoutMillis);
+                args.arg3 = 0;
+                mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE, args),
+                        timeoutMillis);
             }
         }
     }
@@ -4439,10 +4445,11 @@
     }
 
     private void dispatchSubscriptionOverride(INetworkPolicyListener listener, int subId,
-            int overrideMask, int overrideValue) {
+            int overrideMask, int overrideValue, long networkTypeMask) {
         if (listener != null) {
             try {
-                listener.onSubscriptionOverride(subId, overrideMask, overrideValue);
+                listener.onSubscriptionOverride(subId, overrideMask, overrideValue,
+                        networkTypeMask);
             } catch (RemoteException ignored) {
             }
         }
@@ -4543,13 +4550,16 @@
                     return true;
                 }
                 case MSG_SUBSCRIPTION_OVERRIDE: {
-                    final int overrideMask = msg.arg1;
-                    final int overrideValue = msg.arg2;
-                    final int subId = (int) msg.obj;
+                    final SomeArgs args = (SomeArgs) msg.obj;
+                    final int subId = (int) args.arg1;
+                    final int overrideMask = (int) args.arg2;
+                    final int overrideValue = (int) args.arg3;
+                    final long networkTypeMask = (long) args.arg4;
                     final int length = mListeners.beginBroadcast();
                     for (int i = 0; i < length; i++) {
                         final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
-                        dispatchSubscriptionOverride(listener, subId, overrideMask, overrideValue);
+                        dispatchSubscriptionOverride(listener, subId, overrideMask, overrideValue,
+                                networkTypeMask);
                     }
                     mListeners.finishBroadcast();
                     return true;
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 1da5bc6..dc00cb4 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -261,11 +261,12 @@
             mContext.registerReceiver(new BroadcastReceiver() {
                 @Override
                 public void onReceive(Context context, Intent intent) {
-                    populateAllPackagesCacheIfNeeded();
+                    // Post populateAllPackagesCacheIfNeeded to a background thread, since it's
+                    // expensive to run it in broadcast handler thread.
+                    BackgroundThread.getHandler().post(() -> populateAllPackagesCacheIfNeeded());
                     mContext.unregisterReceiver(this);
                 }
-            }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED), /* broadcastPermission */ null,
-                    BackgroundThread.getHandler());
+            }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
         }
 
         private void populateAllPackagesCacheIfNeeded() {
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index c712431..08e55d3 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -34,6 +34,8 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
+import android.provider.DeviceConfig;
+import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.StatsLog;
@@ -84,6 +86,12 @@
 
     // Used for calculating space threshold for downgrading unused apps.
     private static final int LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE = 2;
+    private static final int DEFAULT_INACTIVE_APP_THRESHOLD_DAYS = 10;
+
+    private static final String DOWNGRADE_UNUSED_APPS_ENABLED = "downgrade_unused_apps_enabled";
+    private static final String INACTIVE_APP_THRESHOLD_DAYS = "inactive_app_threshold_days";
+    private static final String LOW_STORAGE_MULTIPLIER_FOR_DOWNGRADE =
+            "low_storage_threshold_multiplier_for_downgrade";
 
     /**
      * Set of failed packages remembered across job runs.
@@ -103,8 +111,6 @@
     private final AtomicBoolean mExitPostBootUpdate = new AtomicBoolean(false);
 
     private final File mDataDir = Environment.getDataDirectory();
-    private static final long mDowngradeUnusedAppsThresholdInMillis =
-            getDowngradeUnusedAppsThresholdInMillis();
 
     public static void schedule(Context context) {
         if (isBackgroundDexoptDisabled()) {
@@ -346,14 +352,14 @@
             // Only downgrade apps when space is low on device.
             // Threshold is selected above the lowStorageThreshold so that we can pro-actively clean
             // up disk before user hits the actual lowStorageThreshold.
-            final long lowStorageThresholdForDowngrade = LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE
+            final long lowStorageThresholdForDowngrade = getLowThresholdMultiplierForDowngrade()
                     * lowStorageThreshold;
             boolean shouldDowngrade = shouldDowngrade(lowStorageThresholdForDowngrade);
             Log.d(TAG, "Should Downgrade " + shouldDowngrade);
             if (shouldDowngrade) {
                 Set<String> unusedPackages =
-                        pm.getUnusedPackages(mDowngradeUnusedAppsThresholdInMillis);
-                Log.d(TAG, "Unsused Packages " +  String.join(",", unusedPackages));
+                        pm.getUnusedPackages(getDowngradeUnusedAppsThresholdInMillis());
+                Log.d(TAG, "Unused Packages " +  String.join(",", unusedPackages));
 
                 if (!unusedPackages.isEmpty()) {
                     for (String pkg : unusedPackages) {
@@ -362,12 +368,9 @@
                             // Should be aborted by the scheduler.
                             return abortCode;
                         }
-                        if (downgradePackage(pm, pkg, /*isForPrimaryDex*/ true)) {
+                        if (downgradePackage(pm, pkg)) {
                             updatedPackages.add(pkg);
                         }
-                        if (supportSecondaryDex) {
-                            downgradePackage(pm, pkg, /*isForPrimaryDex*/ false);
-                        }
                     }
 
                     pkgs = new ArraySet<>(pkgs);
@@ -415,39 +418,45 @@
      * Try to downgrade the package to a smaller compilation filter.
      * eg. if the package is in speed-profile the package will be downgraded to verify.
      * @param pm PackageManagerService
-     * @param pkg The package to be downgraded.
-     * @param isForPrimaryDex. Apps can have several dex file, primary and secondary.
-     * @return true if the package was downgraded.
+     * @param pkg The package to be downgraded
+     * @return true if the package was downgraded
      */
-    private boolean downgradePackage(PackageManagerService pm, String pkg,
-            boolean isForPrimaryDex) {
+    private boolean downgradePackage(PackageManagerService pm, String pkg) {
         Log.d(TAG, "Downgrading " + pkg);
-        boolean dex_opt_performed = false;
+        boolean downgradedPrimary = false;
         int reason = PackageManagerService.REASON_INACTIVE_PACKAGE_DOWNGRADE;
         int dexoptFlags = DexoptOptions.DEXOPT_BOOT_COMPLETE
                 | DexoptOptions.DEXOPT_IDLE_BACKGROUND_JOB
                 | DexoptOptions.DEXOPT_DOWNGRADE;
+
         long package_size_before = getPackageSize(pm, pkg);
-
-        if (isForPrimaryDex) {
-            // This applies for system apps or if packages location is not a directory, i.e.
-            // monolithic install.
-            if (!pm.canHaveOatDir(pkg)) {
-                // For apps that don't have the oat directory, instead of downgrading,
-                // remove their compiler artifacts from dalvik cache.
-                pm.deleteOatArtifactsOfPackage(pkg);
-            } else {
-                dex_opt_performed = performDexOptPrimary(pm, pkg, reason, dexoptFlags);
-            }
+        // An aggressive downgrade deletes the oat files.
+        boolean aggressive = false;
+        // This applies for system apps or if packages location is not a directory, i.e.
+        // monolithic install.
+        if (!pm.canHaveOatDir(pkg)) {
+            // For apps that don't have the oat directory, instead of downgrading,
+            // remove their compiler artifacts from dalvik cache.
+            pm.deleteOatArtifactsOfPackage(pkg);
+            aggressive = true;
+            downgradedPrimary = true;
         } else {
-            dex_opt_performed = performDexOptSecondary(pm, pkg, reason, dexoptFlags);
+            downgradedPrimary = performDexOptPrimary(pm, pkg, reason, dexoptFlags);
+
+            if (supportSecondaryDex()) {
+                performDexOptSecondary(pm, pkg, reason, dexoptFlags);
+            }
         }
 
-        if (dex_opt_performed) {
+        // This metric aims to log the storage savings when downgrading.
+        // The way disk size is measured using getPackageSize only looks at the primary apks.
+        // Any logs that are due to secondary dex files will show 0% size reduction and pollute
+        // the metrics.
+        if (downgradedPrimary) {
             StatsLog.write(StatsLog.APP_DOWNGRADED, pkg, package_size_before,
-                    getPackageSize(pm, pkg), /*aggressive=*/ false);
+                    getPackageSize(pm, pkg), aggressive);
         }
-        return dex_opt_performed;
+        return downgradedPrimary;
     }
 
     private boolean supportSecondaryDex() {
@@ -471,7 +480,7 @@
      * concurrent jobs because PackageDexOptimizer.performDexOpt is synchronized.
      * @param pm An instance of PackageManagerService
      * @param pkg The package to be downgraded.
-     * @param isForPrimaryDex. Apps can have several dex file, primary and secondary.
+     * @param isForPrimaryDex Apps can have several dex file, primary and secondary.
      * @return true if the package was downgraded.
      */
     private boolean optimizePackage(PackageManagerService pm, String pkg,
@@ -588,12 +597,6 @@
         // the checks above. This check is not "live" - the value is determined by a background
         // restart with a period of ~1 minute.
         PackageManagerService pm = (PackageManagerService)ServiceManager.getService("package");
-        if (pm.isStorageLow()) {
-            if (DEBUG_DEXOPT) {
-                Log.i(TAG, "Low storage, skipping this run");
-            }
-            return false;
-        }
 
         final ArraySet<String> pkgs = pm.getOptimizablePackages();
         if (pkgs.isEmpty()) {
@@ -643,17 +646,77 @@
     }
 
     private static long getDowngradeUnusedAppsThresholdInMillis() {
+        long defaultValue = Long.MAX_VALUE;
+        if (isDowngradeFeatureEnabled()) {
+            return getInactiveAppsThresholdMillis();
+        }
         final String sysPropKey = "pm.dexopt.downgrade_after_inactive_days";
         String sysPropValue = SystemProperties.get(sysPropKey);
         if (sysPropValue == null || sysPropValue.isEmpty()) {
             Log.w(TAG, "SysProp " + sysPropKey + " not set");
-            return Long.MAX_VALUE;
+            return defaultValue;
         }
-        return TimeUnit.DAYS.toMillis(Long.parseLong(sysPropValue));
+        try {
+            return TimeUnit.DAYS.toMillis(Long.parseLong(sysPropValue));
+        } catch (NumberFormatException e) {
+            Log.w(TAG, "Couldn't parse long for pm.dexopt.downgrade_after_inactive_days: "
+                    + sysPropValue + ". Returning default value instead.");
+            return defaultValue;
+        }
     }
 
     private static boolean isBackgroundDexoptDisabled() {
         return SystemProperties.getBoolean("pm.dexopt.disable_bg_dexopt" /* key */,
                 false /* default */);
     }
+
+    private static boolean isDowngradeFeatureEnabled() {
+        // DeviceConfig enables the control of on device features via remotely configurable flags,
+        // compared to SystemProperties which is only a way of sharing info system-widely, but are
+        // not configurable on the server-side.
+        String downgradeUnusedAppsEnabledFlag =
+                DeviceConfig.getProperty(
+                        DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE,
+                        DOWNGRADE_UNUSED_APPS_ENABLED);
+        return !TextUtils.isEmpty(downgradeUnusedAppsEnabledFlag)
+                && Boolean.parseBoolean(downgradeUnusedAppsEnabledFlag);
+    }
+
+    private static long getInactiveAppsThresholdMillis() {
+        long defaultValue = TimeUnit.DAYS.toMillis(DEFAULT_INACTIVE_APP_THRESHOLD_DAYS);
+        String inactiveAppThresholdDaysFlag =
+                DeviceConfig.getProperty(DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE,
+                        INACTIVE_APP_THRESHOLD_DAYS);
+        if (!TextUtils.isEmpty(inactiveAppThresholdDaysFlag)) {
+            try {
+                return TimeUnit.DAYS.toMillis(Long.parseLong(inactiveAppThresholdDaysFlag));
+            } catch (NumberFormatException e) {
+                Log.w(TAG, "Couldn't parse long for " + INACTIVE_APP_THRESHOLD_DAYS + " flag: "
+                        + inactiveAppThresholdDaysFlag + ". Returning default value instead.");
+                return defaultValue;
+            }
+        }
+        return defaultValue;
+    }
+
+    private static int getLowThresholdMultiplierForDowngrade() {
+        int defaultValue = LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE;
+        if (isDowngradeFeatureEnabled()) {
+            String lowStorageThresholdMultiplierFlag =
+                    DeviceConfig.getProperty(DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE,
+                            LOW_STORAGE_MULTIPLIER_FOR_DOWNGRADE);
+            if (!TextUtils.isEmpty(lowStorageThresholdMultiplierFlag)) {
+                try {
+                    return Integer.parseInt(lowStorageThresholdMultiplierFlag);
+                } catch (NumberFormatException e) {
+                    Log.w(TAG, "Couldn't parse long for "
+                            + LOW_STORAGE_MULTIPLIER_FOR_DOWNGRADE + " flag: "
+                            + lowStorageThresholdMultiplierFlag
+                            + ". Returning default value instead.");
+                    return defaultValue;
+                }
+            }
+        }
+        return defaultValue;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 3aeb2b1..b632d18f 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -505,6 +505,11 @@
             params.installFlags &= ~PackageManager.INSTALL_REQUEST_DOWNGRADE;
         }
 
+        if (callingUid != Process.SYSTEM_UID) {
+            // Only system_server can use INSTALL_DISABLE_VERIFICATION.
+            params.installFlags &= ~PackageManager.INSTALL_DISABLE_VERIFICATION;
+        }
+
         boolean isApex = (params.installFlags & PackageManager.INSTALL_APEX) != 0;
         if (params.isStaged || isApex) {
             mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, TAG);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2bf5f4d..41403fd 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2149,6 +2149,14 @@
                     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);
+                    // send broadcast that all consumers of the static shared library have changed
+                    sendPackageChangedBroadcast(pkg.packageName, false /*killFlag*/,
+                            new ArrayList<>(Collections.singletonList(pkg.packageName)),
+                            pkg.applicationInfo.uid);
+                }
             }
 
             // Work that needs to happen on first install within each user
@@ -11878,6 +11886,9 @@
                 }
             }
         }
+        if (reconciledPkg.installResult != null) {
+            reconciledPkg.installResult.libraryConsumers = clientLibPkgs;
+        }
 
         if ((scanFlags & SCAN_BOOTING) != 0) {
             // No apps can run during boot scan, so they don't need to be frozen
@@ -15157,6 +15168,8 @@
         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;
 
         public void setError(int code, String msg) {
             setReturnCode(code);
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 85bc9f3..af1a095 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -94,9 +94,11 @@
 import android.text.format.DateUtils;
 import android.util.ArraySet;
 import android.util.PrintWriterPrinter;
+import android.util.SparseArray;
 
 import com.android.internal.content.PackageHelper;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.LocalServices;
 import com.android.server.SystemConfig;
 
@@ -347,17 +349,33 @@
     }
 
     private int getStagedSessions() {
-        final PrintWriter pw = getOutPrintWriter();
+        final IndentingPrintWriter pw = new IndentingPrintWriter(
+                getOutPrintWriter(), /* singleIndent */ "  ", /* wrapLength */ 120);
         try {
-            List<SessionInfo> stagedSessionsList =
+            List<SessionInfo> stagedSessions =
                     mInterface.getPackageInstaller().getStagedSessions().getList();
-            for (SessionInfo session: stagedSessionsList) {
-                pw.println("appPackageName = " + session.getAppPackageName()
-                        + "; sessionId = " + session.getSessionId()
-                        + "; isStaged = " + session.isStaged()
-                        + "; isStagedSessionReady = " + session.isStagedSessionReady()
-                        + "; isStagedSessionApplied = " + session.isStagedSessionApplied()
-                        + "; isStagedSessionFailed = " + session.isStagedSessionFailed() + ";");
+            final SparseArray<SessionInfo> sessionById = new SparseArray<>(stagedSessions.size());
+            for (SessionInfo session : stagedSessions) {
+                sessionById.put(session.getSessionId(), session);
+            }
+            for (SessionInfo session: stagedSessions) {
+                if (session.getParentSessionId() != SessionInfo.INVALID_ID) {
+                    continue;
+                }
+                printStagedSession(session, pw);
+                if (session.isMultiPackage()) {
+                    pw.increaseIndent();
+                    final int[] childIds = session.getChildSessionIds();
+                    for (int i = 0; i < childIds.length; i++) {
+                        final SessionInfo childSession = sessionById.get(childIds[i]);
+                        if (childSession == null) {
+                            pw.println("sessionId = " + childIds[i] + "; not found");
+                        } else {
+                            printStagedSession(childSession, pw);
+                        }
+                    }
+                    pw.decreaseIndent();
+                }
             }
         } catch (RemoteException e) {
             pw.println("Failure ["
@@ -368,6 +386,15 @@
         return 1;
     }
 
+    private static void printStagedSession(SessionInfo session, PrintWriter pw) {
+        pw.println("sessionId = " + session.getSessionId()
+                + "; appPackageName = " + session.getAppPackageName()
+                + "; isStaged = " + session.isStaged()
+                + "; isReady = " + session.isStagedSessionReady()
+                + "; isApplied = " + session.isStagedSessionApplied()
+                + "; isFailed = " + session.isStagedSessionFailed() + ";");
+    }
+
     private int uninstallSystemUpdates() {
         final PrintWriter pw = getOutPrintWriter();
         List<String> failedUninstalls = new LinkedList<>();
@@ -3097,7 +3124,7 @@
         pw.println("       [--user USER_ID] INTENT");
         pw.println("    Prints all broadcast receivers that can handle the given INTENT.");
         pw.println("");
-        pw.println("  install [-lrtsfdgw] [-i PACKAGE] [--user USER_ID|all|current]");
+        pw.println("  install [-rtsfdgw] [-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]");
@@ -3108,7 +3135,6 @@
         pw.println("       [PATH|-]");
         pw.println("    Install an application.  Must provide the apk data to install, either as a");
         pw.println("    file path or '-' to read from stdin.  Options are:");
-        pw.println("      -l: forward lock application");
         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");
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 1fe5512..65fb35d 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -4180,6 +4180,17 @@
             }
             return userData == null ? null : userData.info;
         }
+
+        public @NonNull UserInfo[] getUserInfos() {
+            synchronized (mUsersLock) {
+                int userSize = mUsers.size();
+                UserInfo[] allInfos = new UserInfo[userSize];
+                for (int i = 0; i < userSize; i++) {
+                    allInfos[i] = mUsers.valueAt(i).info;
+                }
+                return allInfos;
+            }
+        }
     }
 
     /* Remove all the users except of the system one. */
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 5a410d7..22929d8 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -650,9 +650,9 @@
     private void updatePermissionFlagsInternal(String permName, String packageName, int flagMask,
             int flagValues, int callingUid, int userId, boolean overridePolicy,
             PermissionCallback callback) {
-        if (ApplicationPackageManager.DEBUG_TRACE_GRANTS
+        if (ApplicationPackageManager.DEBUG_TRACE_PERMISSION_UPDATES
                 && ApplicationPackageManager.shouldTraceGrant(packageName, permName, userId)) {
-            Log.i(TAG, "System is updating flags for "
+            Log.i(TAG, "System is updating flags for " + packageName + " "
                             + permName + " for user " + userId  + " "
                             + DebugUtils.flagsToString(
                                     PackageManager.class, "FLAG_PERMISSION_", flagMask)
@@ -1185,7 +1185,7 @@
             boolean overridePolicy, int callingUid, final int userId, PermissionCallback callback) {
         if (ApplicationPackageManager.DEBUG_TRACE_GRANTS
                 && ApplicationPackageManager.shouldTraceGrant(packageName, permName, userId)) {
-            Log.i(TAG, "System is granting "
+            Log.i(TAG, "System is granting " + packageName + " "
                     + permName + " for user " + userId + " on behalf of uid " + callingUid
                     + " " + mPackageManagerInt.getNameForUid(callingUid),
                     new RuntimeException());
@@ -1232,7 +1232,8 @@
             return;
         }
 
-        final int uid = UserHandle.getUid(userId, pkg.applicationInfo.uid);
+        final int uid = UserHandle.getUid(userId,
+                UserHandle.getAppId(pkg.applicationInfo.uid));
 
         final PackageSetting ps = (PackageSetting) pkg.mExtras;
         final PermissionsState permissionsState = ps.getPermissionsState();
@@ -1344,9 +1345,9 @@
     // TODO swap permission name and package name
     private void revokeRuntimePermissionInternal(String permName, String packageName,
             boolean overridePolicy, int callingUid, final int userId, PermissionCallback callback) {
-        if (ApplicationPackageManager.DEBUG_TRACE_GRANTS
+        if (ApplicationPackageManager.DEBUG_TRACE_PERMISSION_UPDATES
                 && ApplicationPackageManager.shouldTraceGrant(packageName, permName, userId)) {
-            Log.i(TAG, "System is revoking "
+            Log.i(TAG, "System is revoking " + packageName + " "
                             + permName + " for user " + userId + " on behalf of uid " + callingUid
                             + " " + mPackageManagerInt.getNameForUid(callingUid),
                     new RuntimeException());
@@ -1432,7 +1433,8 @@
         }
 
         if (callback != null) {
-            callback.onPermissionRevoked(pkg.applicationInfo.uid, userId);
+            callback.onPermissionRevoked(UserHandle.getUid(userId,
+                    UserHandle.getAppId(pkg.applicationInfo.uid)), userId);
         }
 
         if (bp.isRuntime()) {
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index bfd280c..ddbd9c9 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -282,15 +282,6 @@
                     rollbacks.add(rollback.info);
                 }
             }
-
-            // Also return new rollbacks for which the PackageRollbackInfo is complete.
-            for (NewRollback newRollback : mNewRollbacks) {
-                if (newRollback.rollback.info.getPackages().size()
-                        == newRollback.packageSessionIds.length
-                        && !newRollback.isCancelled) {
-                    rollbacks.add(newRollback.rollback.info);
-                }
-            }
             return new ParceledListSlice<>(rollbacks);
         }
     }
diff --git a/services/core/java/com/android/server/storage/StorageSessionController.java b/services/core/java/com/android/server/storage/StorageSessionController.java
new file mode 100644
index 0000000..2d36a0d
--- /dev/null
+++ b/services/core/java/com/android/server/storage/StorageSessionController.java
@@ -0,0 +1,217 @@
+/*
+ * 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.storage;
+
+import android.Manifest;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.ParcelFileDescriptor;
+import android.os.storage.VolumeInfo;
+import android.provider.MediaStore;
+import android.service.storage.ExternalStorageService;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+
+/**
+ * Controls storage sessions for users initiated by the {@link StorageManagerService}.
+ * Each user on the device will be represented by a {@link StorageUserConnection}.
+ */
+public final class StorageSessionController {
+    private static final String TAG = "StorageSessionController";
+
+    private final Object mLock = new Object();
+    private final Context mContext;
+    private final Callback mCallback;
+    @GuardedBy("mLock")
+    private ComponentName mExternalStorageServiceComponent;
+    @GuardedBy("mLock")
+    private final SparseArray<StorageUserConnection> mConnections = new SparseArray<>();
+
+    public StorageSessionController(Context context, Callback callback) {
+        mContext = Preconditions.checkNotNull(context);
+        mCallback = Preconditions.checkNotNull(callback);
+    }
+
+    /**
+     * Starts a storage session associated with {@code deviceFd} for {@code vol}.
+     * Does nothing if a session is already started or starting. If the user associated with
+     * {@code vol} is not yet ready, the session will be retried {@link #onUserStarted}.
+     *
+     * A session must be ended with {@link #endSession} when no longer required.
+     */
+    public void onVolumeMounted(int userId, FileDescriptor deviceFd, VolumeInfo vol) {
+        if (deviceFd == null) {
+            Slog.w(TAG, "Null device fd. Session not started for " + vol);
+            return;
+        }
+
+        // Get realpath for the fd, paths that are not /dev/null need additional
+        // setup by the ExternalStorageService before they can be ready
+        String realPath;
+        try {
+            realPath = ParcelFileDescriptor.getFile(deviceFd).getPath();
+        } catch (IOException e) {
+            Slog.wtf(TAG, "Could not get real path from fd: " + deviceFd, e);
+            return;
+        }
+
+        if ("/dev/null".equals(realPath)) {
+            Slog.i(TAG, "Volume ready for use: " + vol);
+            return;
+        }
+
+        synchronized (mLock) {
+            StorageUserConnection connection = mConnections.get(userId);
+            if (connection == null) {
+                Slog.i(TAG, "Creating new session for vol: " + vol);
+                connection = new StorageUserConnection(mContext, userId, this);
+                mConnections.put(userId, connection);
+            }
+            try {
+                Slog.i(TAG, "Starting session for vol: " + vol);
+                connection.startSession(deviceFd, vol);
+            } catch (ExternalStorageServiceException e) {
+                Slog.e(TAG, "Failed to start session for vol: " + vol, e);
+            }
+        }
+    }
+
+    /**
+     * Ends a storage session for {@code vol}. Does nothing if the session is already
+     * ended or ending. Ending a session discards all resources associated with that session.
+     */
+    public void onVolumeUnmounted(int userId, VolumeInfo vol) {
+        synchronized (mLock) {
+            StorageUserConnection connection = mConnections.get(userId);
+            if (connection != null) {
+                Slog.i(TAG, "Ending session for vol: " + vol);
+                try {
+                    if (connection.endSession(vol)) {
+                        mConnections.remove(userId);
+                    }
+                } catch (ExternalStorageServiceException e) {
+                    Slog.e(TAG, "Failed to end session for vol: " + vol, e);
+                }
+            } else {
+                Slog.w(TAG, "Session already ended for vol: " + vol);
+            }
+        }
+    }
+
+    /** Restarts all sessions for {@code userId}. */
+    public void onUserStarted(int userId) {
+        synchronized (mLock) {
+            StorageUserConnection connection = mConnections.get(userId);
+            if (connection != null) {
+                try {
+                    Slog.i(TAG, "Restarting all sessions for user: " + userId);
+                    connection.startAllSessions();
+                } catch (ExternalStorageServiceException e) {
+                    Slog.e(TAG, "Failed to start all sessions", e);
+                }
+            } else {
+                // TODO(b/135341433): What does this mean in multi-user
+            }
+        }
+    }
+
+    /** Ends all sessions for {@code userId}. */
+    public void onUserRemoved(int userId) {
+        synchronized (mLock) {
+            StorageUserConnection connection = mConnections.get(userId);
+            if (connection != null) {
+                try {
+                    Slog.i(TAG, "Ending all sessions for user: " + userId);
+                    connection.endAllSessions();
+                    mConnections.remove(userId);
+                } catch (ExternalStorageServiceException e) {
+                    Slog.e(TAG, "Failed to end all sessions", e);
+                }
+            } else {
+                // TODO(b/135341433): What does this mean in multi-user
+            }
+        }
+    }
+
+    /** Returns the {@link ExternalStorageService} component name. */
+    @Nullable
+    public ComponentName getExternalStorageServiceComponentName() {
+        synchronized (mLock) {
+            if (mExternalStorageServiceComponent == null) {
+                ProviderInfo provider = mContext.getPackageManager().resolveContentProvider(
+                        MediaStore.AUTHORITY, PackageManager.MATCH_DIRECT_BOOT_AWARE
+                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+                        | PackageManager.MATCH_SYSTEM_ONLY);
+
+                if (provider == null) {
+                    Slog.e(TAG, "No valid MediaStore provider found.");
+                }
+                String packageName = provider.applicationInfo.packageName;
+
+                Intent intent = new Intent(ExternalStorageService.SERVICE_INTERFACE);
+                intent.setPackage(packageName);
+                ResolveInfo resolveInfo = mContext.getPackageManager().resolveService(intent,
+                        PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
+                if (resolveInfo == null || resolveInfo.serviceInfo == null) {
+                    Slog.e(TAG, "No valid ExternalStorageService component found.");
+                    return null;
+                }
+
+                ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+                ComponentName name = new ComponentName(serviceInfo.packageName, serviceInfo.name);
+                if (!Manifest.permission.BIND_EXTERNAL_STORAGE_SERVICE
+                        .equals(serviceInfo.permission)) {
+                    Slog.e(TAG, name.flattenToShortString() + " does not require permission "
+                            + Manifest.permission.BIND_EXTERNAL_STORAGE_SERVICE);
+                    return null;
+                }
+                mExternalStorageServiceComponent = name;
+            }
+            return mExternalStorageServiceComponent;
+        }
+    }
+
+    /** Returns the {@link StorageManagerService} callback. */
+    public Callback getCallback() {
+        return mCallback;
+    }
+
+    /** Callback to listen to session events from the {@link StorageSessionController}. */
+    public interface Callback {
+        /** Called when a {@link StorageUserConnection} is disconnected. */
+        void onUserDisconnected(int userId);
+    }
+
+    /** Exception thrown when communication with the {@link ExternalStorageService}. */
+    public static class ExternalStorageServiceException extends Exception {
+        public ExternalStorageServiceException(Throwable cause) {
+            super(cause);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/storage/StorageUserConnection.java b/services/core/java/com/android/server/storage/StorageUserConnection.java
new file mode 100644
index 0000000..ff9c900
--- /dev/null
+++ b/services/core/java/com/android/server/storage/StorageUserConnection.java
@@ -0,0 +1,319 @@
+/*
+ * 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.storage;
+
+import static android.service.storage.ExternalStorageService.EXTRA_ERROR;
+import static android.service.storage.ExternalStorageService.FLAG_SESSION_ATTRIBUTE_INDEXABLE;
+import static android.service.storage.ExternalStorageService.FLAG_SESSION_TYPE_FUSE;
+
+import static com.android.server.storage.StorageSessionController.ExternalStorageServiceException;
+
+import android.annotation.MainThread;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.ParcelableException;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.storage.VolumeInfo;
+import android.service.storage.ExternalStorageService;
+import android.service.storage.IExternalStorageService;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Controls the lifecycle of the {@link ActiveConnection} to an {@link ExternalStorageService}
+ * for a user and manages storage sessions represented by a {@link Session}.
+ */
+public final class StorageUserConnection {
+    private static final String TAG = "StorageUserConnection";
+
+    private final Object mLock = new Object();
+    private final Context mContext;
+    private final int mUserId;
+    private final StorageSessionController mSessionController;
+    private final ActiveConnection mActiveConnection = new ActiveConnection();
+    @GuardedBy("mLock") private final Map<String, Session> mSessions = new HashMap<>();
+
+    public StorageUserConnection(Context context, int userId, StorageSessionController controller) {
+        mContext = Preconditions.checkNotNull(context);
+        mUserId = Preconditions.checkArgumentNonnegative(userId);
+        mSessionController = controller;
+    }
+
+    /** Starts a session for a user */
+    public void startSession(FileDescriptor deviceFd, VolumeInfo vol)
+            throws ExternalStorageServiceException {
+        String sessionId = vol.getId();
+        String upperPath = vol.getPath().getPath();
+        String lowerPath = vol.getInternalPath().getPath();
+        Slog.i(TAG, "Starting session with id: " + sessionId + " and upperPath: " + upperPath
+                + " and lowerPath: " + lowerPath);
+        Session session = new Session(sessionId, deviceFd, upperPath, lowerPath);
+        synchronized (mLock) {
+            // TODO(b/135341433): Ensure we don't replace a session without ending the previous
+            mSessions.put(sessionId, session);
+            // TODO(b/135341433): If this fails, maybe its at boot, how to handle if not boot?
+            mActiveConnection.startSessionLocked(session);
+        }
+    }
+
+    /**
+     * Ends a session for a user.
+     *
+     * @return {@code true} if there are no more sessions for this user, {@code false} otherwise
+     **/
+    public boolean endSession(VolumeInfo vol) throws ExternalStorageServiceException {
+        synchronized (mLock) {
+            Session session = mSessions.remove(vol.getId());
+            if (session != null) {
+                mActiveConnection.endSessionLocked(session);
+                mSessions.remove(session.sessionId);
+            }
+            boolean isAllSessionsEnded = mSessions.isEmpty();
+            if (isAllSessionsEnded) {
+                mActiveConnection.close();
+            }
+            return isAllSessionsEnded;
+        }
+    }
+
+    /** Starts all available sessions for a user */
+    public void startAllSessions() throws ExternalStorageServiceException {
+        synchronized (mLock) {
+            for (Session session : mSessions.values()) {
+                mActiveConnection.startSessionLocked(session);
+            }
+        }
+    }
+
+    /** Ends all available sessions for a user */
+    public void endAllSessions() throws ExternalStorageServiceException {
+        synchronized (mLock) {
+            for (Session session : mSessions.values()) {
+                mActiveConnection.endSessionLocked(session);
+                mSessions.remove(session.sessionId);
+            }
+            mActiveConnection.close();
+        }
+    }
+
+    private final class ActiveConnection implements AutoCloseable {
+        // Lifecycle connection to the external storage service, needed to unbind.
+        // We should only try to bind if mServiceConnection is null.
+        // Non-null indicates we are connected or connecting.
+        @GuardedBy("mLock") @Nullable private ServiceConnection mServiceConnection;
+        // Binder object representing the external storage service.
+        // Non-null indicates we are connected
+        @GuardedBy("mLock") @Nullable private IExternalStorageService mRemote;
+        // Exception, if any, thrown from #startSessionLocked or #endSessionLocked
+        // Local variables cannot be referenced from a lambda expression :( so we
+        // save the exception received in the callback here. Since we guard access
+        // (and clear the exception state) with the same lock which we hold during
+        // the entire transaction, there is no risk of race.
+        @GuardedBy("mLock") @Nullable private ParcelableException mLastException;
+
+        @Override
+        public void close() {
+            synchronized (mLock) {
+                if (mServiceConnection != null) {
+                    mContext.unbindService(mServiceConnection);
+                }
+                mServiceConnection = null;
+                mRemote = null;
+            }
+        }
+
+        public void startSessionLocked(Session session) throws ExternalStorageServiceException {
+            if (mServiceConnection == null || mRemote == null) {
+                if (mServiceConnection == null) {
+                    // Not bound
+                    bindLocked();
+                } // else we are binding. In any case when we bind we'll re-start all sessions
+                return;
+            }
+
+            CountDownLatch latch = new CountDownLatch(1);
+            try {
+                mRemote.startSession(session.sessionId,
+                        FLAG_SESSION_TYPE_FUSE | FLAG_SESSION_ATTRIBUTE_INDEXABLE,
+                        new ParcelFileDescriptor(session.deviceFd), session.upperPath,
+                        session.lowerPath, new RemoteCallback(result ->
+                                setResultLocked(latch, result)));
+
+            } catch (RemoteException e) {
+                throw new ExternalStorageServiceException(e);
+            }
+            waitAndReturnResultLocked(latch);
+        }
+
+        public void endSessionLocked(Session session) throws ExternalStorageServiceException {
+            if (mRemote == null) {
+                // TODO(b/135341433): This assumes if there is no connection, there are no
+                // session resources held. Need to document in the ExternalStorageService
+                // API that implementors should end all sessions and clean up resources
+                // when the binding is lost, onDestroy?
+                return;
+            }
+
+            CountDownLatch latch = new CountDownLatch(1);
+            try {
+                mRemote.endSession(session.sessionId, new RemoteCallback(result ->
+                                setResultLocked(latch, result)));
+            } catch (RemoteException e) {
+                throw new ExternalStorageServiceException(e);
+            }
+            waitAndReturnResultLocked(latch);
+        }
+
+        private void setResultLocked(CountDownLatch latch, Bundle result) {
+            mLastException = result.getParcelable(EXTRA_ERROR);
+            latch.countDown();
+        }
+
+        private void waitAndReturnResultLocked(CountDownLatch latch)
+                throws ExternalStorageServiceException {
+            try {
+                // TODO(b/140025078): Call ActivityManager ANR API?
+                latch.await(20, TimeUnit.SECONDS);
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                throw new IllegalStateException(
+                        "Interrupted while waiting for ExternalStorageService result");
+            }
+            if (mLastException != null) {
+                mLastException = null;
+                try {
+                    mLastException.maybeRethrow(IOException.class);
+                } catch (IOException e) {
+                    throw new ExternalStorageServiceException(e);
+                }
+                throw new RuntimeException(mLastException);
+            }
+            mLastException = null;
+        }
+
+        private void bindLocked() {
+            ComponentName name = mSessionController.getExternalStorageServiceComponentName();
+            if (name == null) {
+                Slog.i(TAG, "Not ready to bind to the ExternalStorageService for user " + mUserId);
+                return;
+            }
+
+            ServiceConnection connection = new ServiceConnection() {
+                    @Override
+                    public void onServiceConnected(ComponentName name, IBinder service) {
+                        Slog.i(TAG, "Service: [" + name + "] connected. User [" + mUserId + "]");
+                        handleConnection(service);
+                    }
+
+                    @Override
+                    @MainThread
+                    public void onServiceDisconnected(ComponentName name) {
+                        // Service crashed or process was killed, #onServiceConnected will be called
+                        // Don't need to re-bind.
+                        Slog.i(TAG, "Service: [" + name + "] disconnected. User [" + mUserId + "]");
+                        handleDisconnection();
+                    }
+
+                    @Override
+                    public void onBindingDied(ComponentName name) {
+                        // Application hosting service probably got updated
+                        // Need to re-bind.
+                        Slog.i(TAG, "Service: [" + name + "] died. User [" + mUserId + "]");
+                        handleDisconnection();
+                    }
+
+                    @Override
+                    public void onNullBinding(ComponentName name) {
+                        // Should never happen. Service returned null from #onBind.
+                        Slog.wtf(TAG, "Service: [" + name + "] is null. User [" + mUserId + "]");
+                    }
+
+                    private void handleConnection(IBinder service) {
+                        synchronized (mLock) {
+                            if (mServiceConnection != null) {
+                                mRemote = IExternalStorageService.Stub.asInterface(service);
+                            } else {
+                                Slog.wtf(TAG, "Service connected without a connection object??");
+                            }
+                        }
+
+                        try {
+                            startAllSessions();
+                        } catch (ExternalStorageServiceException e) {
+                            Slog.e(TAG, "Failed to start all sessions", e);
+                        }
+                    }
+
+                    private void handleDisconnection() {
+                        close();
+                        // Clear all sessions because we will need a new device fd since
+                        // StorageManagerService will reset the device mount state and #startSession
+                        // will be called for any required mounts.
+                        synchronized (mLock) {
+                            mSessions.clear();
+                        }
+                        // Notify StorageManagerService so it can restart all necessary sessions
+                        mSessionController.getCallback().onUserDisconnected(mUserId);
+                    }
+                };
+
+            Slog.i(TAG, "Binding to the ExternalStorageService for user " + mUserId);
+            // TODO(b/135341433): Verify required service flags BIND_IMPORTANT?
+            if (mContext.bindServiceAsUser(new Intent().setComponent(name), connection,
+                            Context.BIND_AUTO_CREATE, UserHandle.of(mUserId))) {
+                Slog.i(TAG, "Bound to the ExternalStorageService for user " + mUserId);
+                mServiceConnection = connection;
+                // Reset the remote, we will set when we connect
+                mRemote = null;
+            } else {
+                Slog.w(TAG, "Failed to bind to the ExternalStorageService for user " + mUserId);
+            }
+        }
+    }
+
+    private static final class Session {
+        public final String sessionId;
+        public final FileDescriptor deviceFd;
+        public final String lowerPath;
+        public final String upperPath;
+
+        Session(String sessionId, FileDescriptor deviceFd, String upperPath,
+                String lowerPath) {
+            this.sessionId = sessionId;
+            this.upperPath = upperPath;
+            this.lowerPath = lowerPath;
+            this.deviceFd = deviceFd;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index fc36e99..36e906c 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1935,7 +1935,10 @@
      * HistoryRecord.
      * Normally the server-side record will be removed when the client reports back after
      * destruction. If, however, at this point there is no client process attached, the record will
-     * removed immediately.
+     * be removed immediately.
+     *
+     * @return {@code true} if activity was immediately removed from history, {@code false}
+     * otherwise.
      */
     boolean destroyImmediately(boolean removeFromApp, String reason) {
         if (DEBUG_SWITCH || DEBUG_CLEANUP) {
@@ -2918,7 +2921,7 @@
         return false;
     }
 
-    boolean handleAlreadyVisible() {
+    void handleAlreadyVisible() {
         stopFreezingScreenLocked(false);
         try {
             if (returningOptions != null) {
@@ -2926,7 +2929,6 @@
             }
         } catch(RemoteException e) {
         }
-        return mState == RESUMED;
     }
 
     static void activityResumedLocked(IBinder token) {
@@ -3430,8 +3432,8 @@
             return false;
         }
         final ActivityStack stack = getActivityStack();
-        if (stack == null || this == stack.getResumedActivity() || this == stack.mPausingActivity
-                || !mHaveState || !stopped) {
+        if (isState(RESUMED) || stack == null || this == stack.mPausingActivity || !mHaveState
+                || !stopped) {
             // We're not ready for this kind of thing.
             return false;
         }
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 8bdedff..5bd557d 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -2088,15 +2088,12 @@
             boolean aboveTop = top != null;
             final boolean stackShouldBeVisible = shouldBeVisible(starting);
             boolean behindFullscreenActivity = !stackShouldBeVisible;
-            boolean resumeNextActivity = isFocusable() && isInStackLocked(starting) == null;
+            final boolean resumeTopActivity = isFocusable() && isInStackLocked(starting) == null;
             for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
                 final TaskRecord task = mTaskHistory.get(taskNdx);
                 final ArrayList<ActivityRecord> activities = task.mActivities;
                 for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                     final ActivityRecord r = activities.get(activityNdx);
-                    if (r.finishing) {
-                        continue;
-                    }
                     final boolean isTop = r == top;
                     if (aboveTop && !isTop) {
                         continue;
@@ -2112,6 +2109,9 @@
                                 behindFullscreenActivity, r);
                     }
                     if (reallyVisible) {
+                        if (r.finishing) {
+                            continue;
+                        }
                         if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Make visible? " + r
                                 + " finishing=" + r.finishing + " state=" + r.getState());
                         // First: if this is not the current activity being started, make
@@ -2122,15 +2122,8 @@
                         }
 
                         if (!r.attachedToProcess()) {
-                            if (makeVisibleAndRestartIfNeeded(starting, configChanges, isTop,
-                                    resumeNextActivity, r)) {
-                                if (activityNdx >= activities.size()) {
-                                    // Record may be removed if its process needs to restart.
-                                    activityNdx = activities.size() - 1;
-                                } else {
-                                    resumeNextActivity = false;
-                                }
-                            }
+                            makeVisibleAndRestartIfNeeded(starting, configChanges, isTop,
+                                    resumeTopActivity && isTop, r);
                         } else if (r.visible) {
                             // If this activity is already visible, then there is nothing to do here.
                             if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
@@ -2140,10 +2133,7 @@
                                 r.makeClientVisible();
                             }
 
-                            if (r.handleAlreadyVisible()) {
-                                resumeNextActivity = false;
-                            }
-
+                            r.handleAlreadyVisible();
                             if (notifyClients) {
                                 r.makeActiveIfNeeded(starting);
                             }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 3c5947a..f2ca2ba8 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -82,6 +82,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.wm.ActivityStack.ActivityState.DESTROYED;
+import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING;
 import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
 import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME;
 import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
@@ -3237,11 +3239,12 @@
         synchronized (mGlobalLock) {
             final long origId = Binder.clearCallingIdentity();
             try {
-                ActivityRecord r = ActivityRecord.isInStackLocked(token);
-                if (r == null) {
+                final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+                if (r == null || !r.isDestroyable()) {
                     return false;
                 }
-                return r.safelyDestroy("app-req");
+                r.destroyImmediately(true /* removeFromApp */, "app-req");
+                return r.isState(DESTROYING, DESTROYED);
             } finally {
                 Binder.restoreCallingIdentity(origId);
             }
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index d4e95cf..6b2f9da 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -462,7 +462,7 @@
             // new rotation animation after the old one finally finishes. It's better to defer the
             // app transition.
             if (screenRotationAnimation != null && screenRotationAnimation.isAnimating() &&
-                    mService.getDefaultDisplayContentLocked().rotationNeedsUpdate()) {
+                    mDisplayContent.getDisplayRotation().needsUpdate()) {
                 if (DEBUG_APP_TRANSITIONS) {
                     Slog.v(TAG, "Delaying app transition for screen rotation animation to finish");
                 }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e851a06..71a0126 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -130,9 +130,7 @@
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_REMOVING_FOCUS;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_ASSIGN_LAYERS;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
-import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_ACTIVE;
 import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_TIMEOUT;
-import static com.android.server.wm.WindowManagerService.WINDOW_FREEZE_TIMEOUT_DURATION;
 import static com.android.server.wm.WindowManagerService.dipToPixel;
 import static com.android.server.wm.WindowManagerService.logSurface;
 import static com.android.server.wm.WindowState.EXCLUSION_LEFT;
@@ -148,6 +146,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.pm.ActivityInfo.ScreenOrientation;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
@@ -323,7 +322,7 @@
     private final Display mDisplay;
     private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
     private final DisplayPolicy mDisplayPolicy;
-    private DisplayRotation mDisplayRotation;
+    private final DisplayRotation mDisplayRotation;
     DisplayFrames mDisplayFrames;
 
     private final RemoteCallbackList<ISystemGestureExclusionListener>
@@ -352,22 +351,6 @@
     float mCompatibleScreenScale;
 
     /**
-     * Current rotation of the display.
-     * Constants as per {@link android.view.Surface.Rotation}.
-     *
-     * @see #updateRotationUnchecked()
-     */
-    private int mRotation = 0;
-
-    /**
-     * Last applied orientation of the display.
-     * Constants as per {@link android.content.pm.ActivityInfo.ScreenOrientation}.
-     *
-     * @see #updateOrientationFromAppTokens()
-     */
-    private int mLastOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
-
-    /**
      * Orientation forced by some window. If there is no visible window that specifies orientation
      * it is set to {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED}.
      *
@@ -407,7 +390,6 @@
     // Accessed directly by all users.
     private boolean mLayoutNeeded;
     int pendingLayoutChanges;
-    int mDeferredRotationPauseCount;
 
     /**
      * Used to gate application window layout until we have sent the complete configuration.
@@ -1138,25 +1120,17 @@
         return mInsetsStateController;
     }
 
-    @VisibleForTesting
-    void setDisplayRotation(DisplayRotation displayRotation) {
-        mDisplayRotation = displayRotation;
-    }
-
+    @Surface.Rotation
     int getRotation() {
-        return mRotation;
+        return mDisplayRotation.getRotation();
     }
 
-    @VisibleForTesting
-    void setRotation(int newRotation) {
-        mRotation = newRotation;
-        mDisplayRotation.setRotation(newRotation);
-    }
-
+    @ScreenOrientation
     int getLastOrientation() {
-        return mLastOrientation;
+        return mDisplayRotation.getLastOrientation();
     }
 
+    @ScreenOrientation
     int getLastWindowForcedOrientation() {
         return mLastWindowForcedOrientation;
     }
@@ -1166,48 +1140,6 @@
     }
 
     /**
-     * Temporarily pauses rotation changes until resumed.
-     *
-     * This can be used to prevent rotation changes from occurring while the user is
-     * performing certain operations, such as drag and drop.
-     *
-     * This call nests and must be matched by an equal number of calls to
-     * {@link #resumeRotationLocked}.
-     */
-    void pauseRotationLocked() {
-        mDeferredRotationPauseCount++;
-    }
-
-    /**
-     * Resumes normal rotation changes after being paused.
-     */
-    void resumeRotationLocked() {
-        if (mDeferredRotationPauseCount <= 0) {
-            return;
-        }
-
-        mDeferredRotationPauseCount--;
-        if (mDeferredRotationPauseCount == 0) {
-            updateRotationAndSendNewConfigIfNeeded();
-        }
-    }
-
-    /**
-     * If this is true we have updated our desired orientation, but not yet changed the real
-     * orientation our applied our screen rotation animation. For example, because a previous
-     * screen rotation was in progress.
-     *
-     * @return {@code true} if the there is an ongoing rotation change.
-     */
-    boolean rotationNeedsUpdate() {
-        final int lastOrientation = getLastOrientation();
-        final int oldRotation = getRotation();
-
-        final int rotation = mDisplayRotation.rotationForOrientation(lastOrientation, oldRotation);
-        return oldRotation != rotation;
-    }
-
-    /**
      * 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}.
@@ -1225,7 +1157,7 @@
         configureDisplayPolicy();
         setLayoutNeeded();
 
-        boolean configChanged = updateOrientationFromAppTokens();
+        boolean configChanged = updateOrientation();
         final Configuration currentDisplayConfig = getConfiguration();
         mTmpConfiguration.setTo(currentDisplayConfig);
         computeScreenConfiguration(mTmpConfiguration);
@@ -1263,8 +1195,8 @@
     @Override
     boolean onDescendantOrientationChanged(IBinder freezeDisplayToken,
             ConfigurationContainer requestingContainer) {
-        final Configuration config = updateOrientationFromAppTokens(
-                getRequestedOverrideConfiguration(), freezeDisplayToken, false);
+        final Configuration config = updateOrientation(
+                getRequestedOverrideConfiguration(), freezeDisplayToken, false /* forceUpdate */);
         // If display rotation class tells us that it doesn't consider app requested orientation,
         // this display won't rotate just because of an app changes its requested orientation. Thus
         // it indicates that this display chooses not to handle this request.
@@ -1298,31 +1230,35 @@
     /**
      * Determine the new desired orientation of this display.
      *
-     * The orientation is computed from non-application windows first. If none of the
-     * non-application windows specify orientation, the orientation is computed from application
-     * tokens.
-     *
-     * @return {@code true} if the orientation is changed.
+     * @see #getOrientation()
+     * @return {@code true} if the orientation is changed and the caller should call
+     *         {@link #sendNewConfiguration} if the method returns {@code true}.
      */
-    boolean updateOrientationFromAppTokens() {
-        return updateOrientationFromAppTokens(false /* forceUpdate */);
+    boolean updateOrientation() {
+        return mDisplayRotation.updateOrientation(getOrientation(), false /* forceUpdate */);
     }
 
     /**
-     * Update orientation of the target display, returning a non-null new Configuration if it has
+     * Update orientation of the display, returning a non-null new Configuration if it has
      * changed from the current orientation. If a non-null configuration is returned, someone must
      * call {@link WindowManagerService#setNewDisplayOverrideConfiguration(Configuration,
      * DisplayContent)} to tell the window manager it can unfreeze the screen. This will typically
-     * be done by calling {@link WindowManagerService#sendNewConfiguration(int)}.
+     * be done by calling {@link #sendNewConfiguration}.
+     *
+     * @param currentConfig The current requested override configuration (it is usually set from
+     *                      the last {@link #sendNewConfiguration}) of the display. It is used to
+     *                      check if the configuration container has the latest state.
+     * @param freezeDisplayToken Freeze the app window token if the orientation is changed.
+     * @param forceUpdate See {@link DisplayRotation#updateRotationUnchecked(boolean)}
      */
-    Configuration updateOrientationFromAppTokens(Configuration currentConfig,
-            IBinder freezeDisplayToken, boolean forceUpdate) {
+    Configuration updateOrientation(Configuration currentConfig, IBinder freezeDisplayToken,
+            boolean forceUpdate) {
         if (!mDisplayReady) {
             return null;
         }
 
         Configuration config = null;
-        if (updateOrientationFromAppTokens(forceUpdate)) {
+        if (mDisplayRotation.updateOrientation(getOrientation(), forceUpdate)) {
             // If we changed the orientation but mOrientationChangeComplete is already true,
             // we used seamless rotation, and we don't need to freeze the screen.
             if (freezeDisplayToken != null && !mWmService.mRoot.mOrientationChangeComplete) {
@@ -1345,10 +1281,7 @@
             if (currentConfig.diff(mTmpConfiguration) != 0) {
                 mWaitingForConfig = true;
                 setLayoutNeeded();
-                int[] anim = new int[2];
-                getDisplayPolicy().selectRotationAnimationLw(anim);
-
-                mWmService.startFreezingDisplayLocked(anim[0], anim[1], this);
+                mDisplayRotation.prepareNormalRotationAnimation();
                 config = new Configuration(mTmpConfiguration);
             }
         }
@@ -1356,163 +1289,14 @@
         return config;
     }
 
-
-    private boolean updateOrientationFromAppTokens(boolean forceUpdate) {
-        final int req = getOrientation();
-        if (req != mLastOrientation || forceUpdate) {
-            mLastOrientation = req;
-            mDisplayRotation.setCurrentOrientation(req);
-            return updateRotationUnchecked(forceUpdate);
-        }
-        return false;
-    }
-
-    /**
-     * Update rotation of the display and send configuration if the rotation is changed.
-     *
-     * @return {@code true} if the rotation has been changed and the new config is sent.
-     */
-    boolean updateRotationAndSendNewConfigIfNeeded() {
-        final boolean changed = updateRotationUnchecked(false /* forceUpdate */);
-        if (changed) {
-            sendNewConfiguration();
-        }
-        return changed;
-    }
-
     /**
      * Update rotation of the display.
      *
      * @return {@code true} if the rotation has been changed.  In this case YOU MUST CALL
-     *         {@link WindowManagerService#sendNewConfiguration(int)} TO UNFREEZE THE SCREEN.
+     *         {@link #sendNewConfiguration} TO UNFREEZE THE SCREEN.
      */
     boolean updateRotationUnchecked() {
-        return updateRotationUnchecked(false /* forceUpdate */);
-    }
-
-    /**
-     * Update rotation of the DisplayContent with an option to force the update. This updates
-     * the container's perception of rotation and, depending on the top activities, will freeze
-     * the screen or start seamless rotation. The display itself gets rotated in
-     * {@link #applyRotationLocked} during {@link DisplayContent#sendNewConfiguration}.
-     *
-     * @param forceUpdate Force the rotation update. Sometimes in WM we might skip updating
-     *                    orientation because we're waiting for some rotation to finish or display
-     *                    to unfreeze, which results in configuration of the previously visible
-     *                    activity being applied to a newly visible one. Forcing the rotation
-     *                    update allows to workaround this issue.
-     * @return {@code true} if the rotation has been changed.  In this case YOU MUST CALL
-     *         {@link WindowManagerService#sendNewConfiguration(int)} TO COMPLETE THE ROTATION AND
-     *         UNFREEZE THE SCREEN.
-     */
-    boolean updateRotationUnchecked(boolean forceUpdate) {
-        ScreenRotationAnimation screenRotationAnimation;
-        if (!forceUpdate) {
-            if (mDeferredRotationPauseCount > 0) {
-                // Rotation updates have been paused temporarily.  Defer the update until
-                // updates have been resumed.
-                if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, rotation is paused.");
-                return false;
-            }
-
-            screenRotationAnimation =
-                    mWmService.mAnimator.getScreenRotationAnimationLocked(mDisplayId);
-            if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
-                // Rotation updates cannot be performed while the previous rotation change
-                // animation is still in progress.  Skip this update.  We will try updating
-                // again after the animation is finished and the display is unfrozen.
-                if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, animation in progress.");
-                return false;
-            }
-            if (mWmService.mDisplayFrozen) {
-                // Even if the screen rotation animation has finished (e.g. isAnimating
-                // returns false), there is still some time where we haven't yet unfrozen
-                // the display. We also need to abort rotation here.
-                if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
-                        "Deferring rotation, still finishing previous rotation");
-                return false;
-            }
-        }
-
-        if (!mWmService.mDisplayEnabled) {
-            // No point choosing a rotation if the display is not enabled.
-            if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, display is not enabled.");
-            return false;
-        }
-
-        final int oldRotation = mRotation;
-        final int lastOrientation = mLastOrientation;
-        final int rotation = mDisplayRotation.rotationForOrientation(lastOrientation, oldRotation);
-        if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Computed rotation=" + rotation + " for display id="
-                + mDisplayId + " based on lastOrientation=" + lastOrientation
-                + " and oldRotation=" + oldRotation);
-        boolean mayRotateSeamlessly = mDisplayPolicy.shouldRotateSeamlessly(mDisplayRotation,
-                oldRotation, rotation);
-
-        if (mayRotateSeamlessly) {
-            final WindowState seamlessRotated = getWindow((w) -> w.mSeamlesslyRotated);
-            if (seamlessRotated != null && !forceUpdate) {
-                // We can't rotate (seamlessly or not) while waiting for the last seamless rotation
-                // to complete (that is, waiting for windows to redraw). It's tempting to check
-                // w.mSeamlessRotationCount but that could be incorrect in the case of
-                // window-removal.
-                return false;
-            }
-
-            // In the presence of the PINNED stack or System Alert
-            // windows we unfortunately can not seamlessly rotate.
-            if (hasPinnedStack()) {
-                mayRotateSeamlessly = false;
-            }
-            for (int i = 0; i < mWmService.mSessions.size(); i++) {
-                if (mWmService.mSessions.valueAt(i).hasAlertWindowSurfaces()) {
-                    mayRotateSeamlessly = false;
-                    break;
-                }
-            }
-        }
-        final boolean rotateSeamlessly = mayRotateSeamlessly;
-
-        if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + mDisplayId
-                + " selected orientation " + lastOrientation
-                + ", got rotation " + rotation);
-
-        if (oldRotation == rotation) {
-            // No change.
-            return false;
-        }
-
-        if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + mDisplayId
-                + " rotation changed to " + rotation
-                + " from " + oldRotation
-                + ", lastOrientation=" + lastOrientation);
-
-        if (DisplayContent.deltaRotation(rotation, oldRotation) != 2) {
-            mWaitingForConfig = true;
-        }
-
-        mRotation = rotation;
-
-        mWmService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
-        mWmService.mH.sendNewMessageDelayed(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT,
-                this, WINDOW_FREEZE_TIMEOUT_DURATION);
-
-        setLayoutNeeded();
-        final int[] anim = new int[2];
-        mDisplayPolicy.selectRotationAnimationLw(anim);
-
-        if (!rotateSeamlessly) {
-            mWmService.startFreezingDisplayLocked(anim[0], anim[1], this);
-            // startFreezingDisplayLocked can reset the ScreenRotationAnimation.
-        } else {
-            // The screen rotation animation uses a screenshot to freeze the screen
-            // while windows resize underneath.
-            // When we are rotating seamlessly, we allow the elements to transition
-            // to their rotated state independently and without a freeze required.
-            mWmService.startSeamlessRotation();
-        }
-
-        return true;
+        return mDisplayRotation.updateRotationUnchecked(false /* forceUpdate */);
     }
 
     /**
@@ -1523,10 +1307,11 @@
      * @param rotation the rotation to apply.
      */
     void applyRotationLocked(final int oldRotation, final int rotation) {
-        mDisplayRotation.setRotation(rotation);
-        final boolean rotateSeamlessly = mWmService.isRotatingSeamlessly();
-        ScreenRotationAnimation screenRotationAnimation = rotateSeamlessly
+        mDisplayRotation.applyCurrentRotation(rotation);
+        final boolean rotateSeamlessly = mDisplayRotation.isRotatingSeamlessly();
+        final ScreenRotationAnimation screenRotationAnimation = rotateSeamlessly
                 ? null : mWmService.mAnimator.getScreenRotationAnimationLocked(mDisplayId);
+        final Transaction transaction = getPendingTransaction();
         // We need to update our screen size information to match the new rotation. If the rotation
         // has actually changed then this method will return true and, according to the comment at
         // the top of the method, the caller is obligated to call computeNewConfigurationLocked().
@@ -1537,15 +1322,14 @@
         // NOTE: We disable the rotation in the emulator because
         //       it doesn't support hardware OpenGL emulation yet.
         if (screenRotationAnimation != null && screenRotationAnimation.hasScreenshot()) {
-            screenRotationAnimation.setRotation(getPendingTransaction(), rotation);
+            screenRotationAnimation.setRotation(transaction, rotation);
         }
 
         forAllWindows(w -> {
-            w.seamlesslyRotateIfAllowed(getPendingTransaction(), oldRotation, rotation,
-                    rotateSeamlessly);
+            w.seamlesslyRotateIfAllowed(transaction, oldRotation, rotation, rotateSeamlessly);
         }, true /* traverseTopToBottom */);
 
-        mWmService.mDisplayManagerInternal.performTraversal(getPendingTransaction());
+        mWmService.mDisplayManagerInternal.performTraversal(transaction);
         scheduleAnimation();
 
         forAllWindows(w -> {
@@ -1627,19 +1411,20 @@
      */
     private DisplayInfo updateDisplayAndOrientation(int uiMode, Configuration outConfig) {
         // Use the effective "visual" dimensions based on current rotation
-        final boolean rotated = (mRotation == ROTATION_90 || mRotation == ROTATION_270);
+        final int rotation = getRotation();
+        final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
         final int dw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
         final int dh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
 
         // Update application display metrics.
-        final WmDisplayCutout wmDisplayCutout = calculateDisplayCutoutForRotation(mRotation);
+        final WmDisplayCutout wmDisplayCutout = calculateDisplayCutoutForRotation(rotation);
         final DisplayCutout displayCutout = wmDisplayCutout.getDisplayCutout();
 
-        final int appWidth = mDisplayPolicy.getNonDecorDisplayWidth(dw, dh, mRotation, uiMode,
+        final int appWidth = mDisplayPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode,
                 displayCutout);
-        final int appHeight = mDisplayPolicy.getNonDecorDisplayHeight(dw, dh, mRotation, uiMode,
+        final int appHeight = mDisplayPolicy.getNonDecorDisplayHeight(dw, dh, rotation, uiMode,
                 displayCutout);
-        mDisplayInfo.rotation = mRotation;
+        mDisplayInfo.rotation = rotation;
         mDisplayInfo.logicalWidth = dw;
         mDisplayInfo.logicalHeight = dh;
         mDisplayInfo.logicalDensityDpi = mBaseDisplayDensity;
@@ -2044,7 +1829,7 @@
         return mTaskStackContainers.getPinnedStack();
     }
 
-    private boolean hasPinnedStack() {
+    boolean hasPinnedStack() {
         return mTaskStackContainers.getPinnedStack() != null;
     }
 
@@ -2198,6 +1983,11 @@
         return mImeWindowsContainers.forAllWindows(callback, traverseTopToBottom);
     }
 
+    /**
+     * In the general case, the orientation is computed from the above app windows first. If none of
+     * the above app windows specify orientation, the orientation is computed from the child window
+     * container, e.g. {@link AppWindowToken#getOrientation(int)}.
+     */
     @Override
     int getOrientation() {
         final WindowManagerPolicy policy = mWmService.mPolicy;
@@ -2222,8 +2012,8 @@
                 // things aren't stable while the display is frozen, for example the window could be
                 // momentarily unavailable due to activity relaunch.
                 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + mDisplayId
-                        + " is frozen while keyguard locked, return " + mLastOrientation);
-                return mLastOrientation;
+                        + " is frozen while keyguard locked, return " + getLastOrientation());
+                return getLastOrientation();
             }
         } else {
             final int orientation = mAboveAppWindowsContainers.getOrientation();
@@ -2835,7 +2625,7 @@
         }
         proto.write(DPI, mBaseDisplayDensity);
         mDisplayInfo.writeToProto(proto, DISPLAY_INFO);
-        proto.write(ROTATION, mRotation);
+        proto.write(ROTATION, getRotation());
         final ScreenRotationAnimation screenRotationAnimation =
                 mWmService.mAnimator.getScreenRotationAnimationLocked(mDisplayId);
         if (screenRotationAnimation != null) {
@@ -2892,8 +2682,6 @@
 
         pw.println();
         pw.print(prefix); pw.print("mLayoutSeq="); pw.println(mLayoutSeq);
-        pw.print(prefix);
-        pw.print("mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
 
         pw.print("  mCurrentFocus="); pw.println(mCurrentFocus);
         if (mLastFocus != mCurrentFocus) {
@@ -3264,6 +3052,15 @@
         return mTmpWindow != null;
     }
 
+    boolean hasAlertWindowSurfaces() {
+        for (int i = mWmService.mSessions.size() - 1; i >= 0; --i) {
+            if (mWmService.mSessions.valueAt(i).hasAlertWindowSurfaces(this)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Set input method window for the display.
      * @param win Set when window added or Null when destroyed.
@@ -3747,7 +3544,7 @@
 
             if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_CONFIG) != 0) {
                 if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
-                if (updateOrientationFromAppTokens()) {
+                if (updateOrientation()) {
                     setLayoutNeeded();
                     sendNewConfiguration();
                 }
@@ -3887,7 +3684,7 @@
                 calculateDisplayCutoutForRotation(mDisplayInfo.rotation));
         // TODO: Not sure if we really need to set the rotation here since we are updating from
         // the display info above...
-        mDisplayFrames.mRotation = mRotation;
+        mDisplayFrames.mRotation = getRotation();
         mDisplayPolicy.beginLayoutLw(mDisplayFrames, getConfiguration().uiMode);
 
         int seq = mLayoutSeq + 1;
@@ -4002,25 +3799,6 @@
         }
     }
 
-    void onSeamlessRotationTimeout() {
-        // Used to indicate the layout is needed.
-        mTmpWindow = null;
-
-        forAllWindows(w -> {
-            if (!w.mSeamlesslyRotated) {
-                return;
-            }
-            mTmpWindow = w;
-            w.setDisplayLayoutNeeded();
-            w.finishSeamlessRotation(true /* timeout */);
-            mWmService.markForSeamlessRotation(w, false);
-        }, true /* traverseTopToBottom */);
-
-        if (mTmpWindow != null) {
-            mWmService.mWindowPlacerLocked.performSurfacePlacement();
-        }
-    }
-
     void setExitingTokensHasVisible(boolean hasVisible) {
         for (int i = mExitingTokens.size() - 1; i >= 0; i--) {
             mExitingTokens.get(i).hasVisible = hasVisible;
@@ -4502,11 +4280,11 @@
             }
 
             if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
-                    "No app is requesting an orientation, return " + mLastOrientation
+                    "No app is requesting an orientation, return " + getLastOrientation()
                             + " for display id=" + mDisplayId);
             // The next app has not been requested to be visible, so we keep the current orientation
             // to prevent freezing/unfreezing the display too early.
-            return mLastOrientation;
+            return getLastOrientation();
         }
 
         @Override
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index e5962ae..8328770 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -57,10 +57,6 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
-import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE;
-import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT;
-import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
-import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
@@ -257,7 +253,6 @@
     private volatile boolean mNavigationBarCanMove;
     private volatile boolean mNavigationBarLetsThroughTaps;
     private volatile boolean mNavigationBarAlwaysShowOnSideGesture;
-    private volatile boolean mAllowSeamlessRotationDespiteNavBarMoving;
 
     // Written by vr manager thread, only read in this class.
     private volatile boolean mPersistentVrModeEnabled;
@@ -1151,81 +1146,6 @@
     }
 
     /**
-     * Determine the animation to run for a rotation transition based on the
-     * top fullscreen windows {@link WindowManager.LayoutParams#rotationAnimation}
-     * and whether it is currently fullscreen and frontmost.
-     *
-     * @param anim The exiting animation resource id is stored in anim[0], the
-     * entering animation resource id is stored in anim[1].
-     */
-    public void selectRotationAnimationLw(int anim[]) {
-        // If the screen is off or non-interactive, force a jumpcut.
-        final boolean forceJumpcut = !mScreenOnFully || !mService.mPolicy.okToAnimate();
-        if (DEBUG_ANIM) Slog.i(TAG, "selectRotationAnimation mTopFullscreen="
-                + mTopFullscreenOpaqueWindowState + " rotationAnimation="
-                + (mTopFullscreenOpaqueWindowState == null
-                ? "0" : mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation)
-                + " forceJumpcut=" + forceJumpcut);
-        if (forceJumpcut) {
-            anim[0] = R.anim.rotation_animation_jump_exit;
-            anim[1] = R.anim.rotation_animation_enter;
-            return;
-        }
-        if (mTopFullscreenOpaqueWindowState != null) {
-            int animationHint = mTopFullscreenOpaqueWindowState.getRotationAnimationHint();
-            if (animationHint < 0 && mTopIsFullscreen) {
-                animationHint = mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation;
-            }
-            switch (animationHint) {
-                case ROTATION_ANIMATION_CROSSFADE:
-                case ROTATION_ANIMATION_SEAMLESS: // Crossfade is fallback for seamless.
-                    anim[0] = R.anim.rotation_animation_xfade_exit;
-                    anim[1] = R.anim.rotation_animation_enter;
-                    break;
-                case ROTATION_ANIMATION_JUMPCUT:
-                    anim[0] = R.anim.rotation_animation_jump_exit;
-                    anim[1] = R.anim.rotation_animation_enter;
-                    break;
-                case ROTATION_ANIMATION_ROTATE:
-                default:
-                    anim[0] = anim[1] = 0;
-                    break;
-            }
-        } else {
-            anim[0] = anim[1] = 0;
-        }
-    }
-
-    /**
-     * Validate whether the current top fullscreen has specified the same
-     * {@link WindowManager.LayoutParams#rotationAnimation} value as that
-     * being passed in from the previous top fullscreen window.
-     *
-     * @param exitAnimId exiting resource id from the previous window.
-     * @param enterAnimId entering resource id from the previous window.
-     * @param forceDefault For rotation animations only, if true ignore the
-     * animation values and just return false.
-     * @return true if the previous values are still valid, false if they
-     * should be replaced with the default.
-     */
-    public boolean validateRotationAnimationLw(int exitAnimId, int enterAnimId,
-            boolean forceDefault) {
-        switch (exitAnimId) {
-            case R.anim.rotation_animation_xfade_exit:
-            case R.anim.rotation_animation_jump_exit:
-                // These are the only cases that matter.
-                if (forceDefault) {
-                    return false;
-                }
-                int anim[] = new int[2];
-                selectRotationAnimationLw(anim);
-                return (exitAnimId == anim[0] && enterAnimId == anim[1]);
-            default:
-                return true;
-        }
-    }
-
-    /**
      * Called when a new system UI visibility is being reported, allowing
      * the policy to adjust what is actually reported.
      * @param visibility The raw visibility reported by the status bar.
@@ -2388,6 +2308,14 @@
         displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
     }
 
+    WindowState getTopFullscreenOpaqueWindow() {
+        return mTopFullscreenOpaqueWindowState;
+    }
+
+    boolean isTopLayoutFullscreen() {
+        return mTopIsFullscreen;
+    }
+
     /**
      * Called following layout of all windows before each window has policy applied.
      */
@@ -2773,8 +2701,7 @@
         mNavigationBarCanMove =
                 mDisplayContent.mBaseDisplayWidth != mDisplayContent.mBaseDisplayHeight
                         && res.getBoolean(R.bool.config_navBarCanMove);
-        mAllowSeamlessRotationDespiteNavBarMoving =
-                res.getBoolean(R.bool.config_allowSeamlessRotationDespiteNavBarMoving);
+        mDisplayContent.getDisplayRotation().updateUserDependentConfiguration(res);
     }
 
     /**
@@ -3562,45 +3489,6 @@
         return (systemUiFlags & disableNavigationBar) == disableNavigationBar;
     }
 
-    boolean shouldRotateSeamlessly(DisplayRotation displayRotation, int oldRotation,
-            int newRotation) {
-        // For the upside down rotation we don't rotate seamlessly as the navigation
-        // bar moves position.
-        // Note most apps (using orientation:sensor or user as opposed to fullSensor)
-        // will not enter the reverse portrait orientation, so actually the
-        // orientation won't change at all.
-        if (oldRotation == displayRotation.getUpsideDownRotation()
-                || newRotation == displayRotation.getUpsideDownRotation()) {
-            return false;
-        }
-        // If the navigation bar can't change sides, then it will
-        // jump when we change orientations and we don't rotate
-        // seamlessly - unless that is allowed, eg. with gesture
-        // navigation where the navbar is low-profile enough that this isn't very noticeable.
-        if (!navigationBarCanMove() && !mAllowSeamlessRotationDespiteNavBarMoving) {
-            return false;
-        }
-
-        final WindowState w = mTopFullscreenOpaqueWindowState;
-        if (w == null || w != mFocusedWindow) {
-            return false;
-        }
-        // If the bounds of activity window is different from its parent, then reject to be seamless
-        // because the window position may change after rotation that will look like a sudden jump.
-        if (w.mAppToken != null && !w.mAppToken.matchParentBounds()) {
-            return false;
-        }
-
-        // We only enable seamless rotation if the top window has requested
-        // it and is in the fullscreen opaque state. Seamless rotation
-        // requires freezing various Surface states and won't work well
-        // with animations, so we disable it in the animation case for now.
-        if (!w.isAnimatingLw() && w.getAttrs().rotationAnimation == ROTATION_ANIMATION_SEAMLESS) {
-            return true;
-        }
-        return false;
-    }
-
     private final Runnable mHiddenNavPanic = new Runnable() {
         @Override
         public void run() {
@@ -3665,7 +3553,7 @@
     }
 
     void dump(String prefix, PrintWriter pw) {
-        pw.print(prefix); pw.print("DisplayPolicy");
+        pw.print(prefix); pw.println("DisplayPolicy");
         prefix += "  ";
         pw.print(prefix);
         pw.print("mCarDockEnablesAccelerometer="); pw.print(mCarDockEnablesAccelerometer);
@@ -3724,12 +3612,12 @@
             pw.print(prefix); pw.print("mForcingShowNavBarLayer=");
             pw.println(mForcingShowNavBarLayer);
         }
-        pw.print(prefix); pw.print("mTopIsFullscreen="); pw.print(mTopIsFullscreen);
+        pw.print(prefix); pw.print("mTopIsFullscreen="); pw.println(mTopIsFullscreen);
         pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar);
         pw.print(" mForceStatusBarFromKeyguard="); pw.println(mForceStatusBarFromKeyguard);
-        pw.print(" mForceShowSystemBarsFromExternal=");
-        pw.println(mForceShowSystemBarsFromExternal);
-        pw.print(prefix); pw.print("mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn);
+        pw.print(prefix); pw.print("mForceShowSystemBarsFromExternal=");
+        pw.print(mForceShowSystemBarsFromExternal);
+        pw.print(" mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn);
         mStatusBarController.dump(pw, prefix);
         mNavigationBarController.dump(pw, prefix);
 
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 410cc94..4d188f4 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -16,11 +16,21 @@
 
 package com.android.server.wm;
 
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
+
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_ACTIVE;
+import static com.android.server.wm.WindowManagerService.WINDOW_FREEZE_TIMEOUT_DURATION;
 
+import android.annotation.AnimRes;
 import android.annotation.IntDef;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
@@ -28,6 +38,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ActivityInfo.ScreenOrientation;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.database.ContentObserver;
@@ -41,6 +52,7 @@
 import android.util.SparseArray;
 import android.view.Surface;
 
+import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.LocalServices;
 import com.android.server.UiThread;
@@ -59,6 +71,13 @@
 public class DisplayRotation {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayRotation" : TAG_WM;
 
+    private static class RotationAnimationPair {
+        @AnimRes
+        int mEnter;
+        @AnimRes
+        int mExit;
+    }
+
     private final WindowManagerService mService;
     private final DisplayContent mDisplayContent;
     private final DisplayPolicy mDisplayPolicy;
@@ -72,12 +91,30 @@
     private final int mCarDockRotation;
     private final int mDeskDockRotation;
     private final int mUndockedHdmiRotation;
+    private final RotationAnimationPair mTmpRotationAnim = new RotationAnimationPair();
 
     private OrientationListener mOrientationListener;
     private StatusBarManagerInternal mStatusBarManagerInternal;
     private SettingsObserver mSettingsObserver;
 
-    private int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+    @ScreenOrientation
+    private int mCurrentAppOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
+
+    /**
+     * Last applied orientation of the display.
+     *
+     * @see #updateOrientationFromApp
+     */
+    @ScreenOrientation
+    private int mLastOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
+
+    /**
+     * Current rotation of the display.
+     *
+     * @see #updateRotationUnchecked
+     */
+    @Surface.Rotation
+    private int mRotation;
 
     @VisibleForTesting
     int mLandscapeRotation;  // default landscape
@@ -88,11 +125,52 @@
     @VisibleForTesting
     int mUpsideDownRotation; // "other" portrait
 
-    // Behavior of rotation suggestions. (See Settings.Secure.SHOW_ROTATION_SUGGESTION)
+    private boolean mAllowSeamlessRotationDespiteNavBarMoving;
+
+    private int mDeferredRotationPauseCount;
+
+    /**
+     * A count of the windows which are 'seamlessly rotated', e.g. a surface at an old orientation
+     * is being transformed. We freeze orientation updates while any windows are seamlessly rotated,
+     * so we need to track when this hits zero so we can apply deferred orientation updates.
+     */
+    private int mSeamlessRotationCount;
+
+    /**
+     * True in the interval from starting seamless rotation until the last rotated window draws in
+     * the new orientation.
+     */
+    private boolean mRotatingSeamlessly;
+
+    /**
+     * Behavior of rotation suggestions.
+     *
+     * @see Settings.Secure#SHOW_ROTATION_SUGGESTIONS
+     */
     private int mShowRotationSuggestions;
 
-    private int mAllowAllRotations = -1;
+    private static final int ALLOW_ALL_ROTATIONS_UNDEFINED = -1;
+    private static final int ALLOW_ALL_ROTATIONS_DISABLED = 0;
+    private static final int ALLOW_ALL_ROTATIONS_ENABLED = 1;
+
+    @IntDef({ ALLOW_ALL_ROTATIONS_UNDEFINED, ALLOW_ALL_ROTATIONS_DISABLED,
+            ALLOW_ALL_ROTATIONS_ENABLED })
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface AllowAllRotations {}
+
+    /**
+     * Whether to allow the screen to rotate to all rotations (including 180 degree) according to
+     * the sensor even when the current orientation is not
+     * {@link ActivityInfo#SCREEN_ORIENTATION_FULL_SENSOR} or
+     * {@link ActivityInfo#SCREEN_ORIENTATION_FULL_USER}.
+     */
+    @AllowAllRotations
+    private int mAllowAllRotations = ALLOW_ALL_ROTATIONS_UNDEFINED;
+
+    @WindowManagerPolicy.UserRotationMode
     private int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
+
+    @Surface.Rotation
     private int mUserRotation = Surface.ROTATION_0;
 
     /**
@@ -125,6 +203,7 @@
      * 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 mDemoHdmiRotation;
@@ -149,21 +228,17 @@
         mLock = lock;
         isDefaultDisplay = displayContent.isDefaultDisplay;
 
-        mSupportAutoRotation = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_supportAutoRotation);
-        mLidOpenRotation = readRotation(
-                com.android.internal.R.integer.config_lidOpenRotation);
-        mCarDockRotation = readRotation(
-                com.android.internal.R.integer.config_carDockRotation);
-        mDeskDockRotation = readRotation(
-                com.android.internal.R.integer.config_deskDockRotation);
-        mUndockedHdmiRotation = readRotation(
-                com.android.internal.R.integer.config_undockedHdmiRotation);
+        mSupportAutoRotation =
+                mContext.getResources().getBoolean(R.bool.config_supportAutoRotation);
+        mLidOpenRotation = readRotation(R.integer.config_lidOpenRotation);
+        mCarDockRotation = readRotation(R.integer.config_carDockRotation);
+        mDeskDockRotation = readRotation(R.integer.config_deskDockRotation);
+        mUndockedHdmiRotation = readRotation(R.integer.config_undockedHdmiRotation);
 
         if (isDefaultDisplay) {
             final Handler uiHandler = UiThread.getHandler();
             mOrientationListener = new OrientationListener(mContext, uiHandler);
-            mOrientationListener.setCurrentRotation(displayContent.getRotation());
+            mOrientationListener.setCurrentRotation(mRotation);
             mSettingsObserver = new SettingsObserver(uiHandler);
             mSettingsObserver.observe();
         }
@@ -188,12 +263,21 @@
         return -1;
     }
 
+    /**
+     * Updates the configuration which may have different values depending on current user, e.g.
+     * runtime resource overlay.
+     */
+    void updateUserDependentConfiguration(Resources currentUserRes) {
+        mAllowSeamlessRotationDespiteNavBarMoving =
+                currentUserRes.getBoolean(R.bool.config_allowSeamlessRotationDespiteNavBarMoving);
+    }
+
     void configure(int width, int height, int shortSizeDp, int longSizeDp) {
         final Resources res = mContext.getResources();
         if (width > height) {
             mLandscapeRotation = Surface.ROTATION_0;
             mSeascapeRotation = Surface.ROTATION_180;
-            if (res.getBoolean(com.android.internal.R.bool.config_reverseDefaultRotation)) {
+            if (res.getBoolean(R.bool.config_reverseDefaultRotation)) {
                 mPortraitRotation = Surface.ROTATION_90;
                 mUpsideDownRotation = Surface.ROTATION_270;
             } else {
@@ -203,7 +287,7 @@
         } else {
             mPortraitRotation = Surface.ROTATION_0;
             mUpsideDownRotation = Surface.ROTATION_180;
-            if (res.getBoolean(com.android.internal.R.bool.config_reverseDefaultRotation)) {
+            if (res.getBoolean(R.bool.config_reverseDefaultRotation)) {
                 mLandscapeRotation = Surface.ROTATION_270;
                 mSeascapeRotation = Surface.ROTATION_90;
             } else {
@@ -246,19 +330,325 @@
                 && !"true".equals(SystemProperties.get("config.override_forced_orient"));
     }
 
-    void setRotation(int rotation) {
+    void applyCurrentRotation(@Surface.Rotation int rotation) {
         if (mOrientationListener != null) {
             mOrientationListener.setCurrentRotation(rotation);
         }
     }
 
-    void setCurrentOrientation(int newOrientation) {
+    @VisibleForTesting
+    void setRotation(@Surface.Rotation int rotation) {
+        mRotation = rotation;
+    }
+
+    @Surface.Rotation
+    int getRotation() {
+        return mRotation;
+    }
+
+    @ScreenOrientation
+    int getLastOrientation() {
+        return mLastOrientation;
+    }
+
+    boolean updateOrientation(@ScreenOrientation int newOrientation, boolean forceUpdate) {
+        if (newOrientation == mLastOrientation && !forceUpdate) {
+            return false;
+        }
+        mLastOrientation = newOrientation;
         if (newOrientation != mCurrentAppOrientation) {
             mCurrentAppOrientation = newOrientation;
             if (isDefaultDisplay) {
                 updateOrientationListenerLw();
             }
         }
+        return updateRotationUnchecked(forceUpdate);
+    }
+
+    /**
+     * Update rotation of the display and send configuration if the rotation is changed.
+     *
+     * @return {@code true} if the rotation has been changed and the new config is sent.
+     */
+    boolean updateRotationAndSendNewConfigIfChanged() {
+        final boolean changed = updateRotationUnchecked(false /* forceUpdate */);
+        if (changed) {
+            mDisplayContent.sendNewConfiguration();
+        }
+        return changed;
+    }
+
+    /**
+     * Update rotation with an option to force the update. This updates the container's perception
+     * of rotation and, depending on the top activities, will freeze the screen or start seamless
+     * rotation. The display itself gets rotated in {@link DisplayContent#applyRotationLocked}
+     * during {@link DisplayContent#sendNewConfiguration}.
+     *
+     * @param forceUpdate Force the rotation update. Sometimes in WM we might skip updating
+     *                    orientation because we're waiting for some rotation to finish or display
+     *                    to unfreeze, which results in configuration of the previously visible
+     *                    activity being applied to a newly visible one. Forcing the rotation
+     *                    update allows to workaround this issue.
+     * @return {@code true} if the rotation has been changed. In this case YOU MUST CALL
+     *         {@link DisplayContent#sendNewConfiguration} TO COMPLETE THE ROTATION AND UNFREEZE
+     *         THE SCREEN.
+     */
+    boolean updateRotationUnchecked(boolean forceUpdate) {
+        final int displayId = mDisplayContent.getDisplayId();
+        if (!forceUpdate) {
+            if (mDeferredRotationPauseCount > 0) {
+                // Rotation updates have been paused temporarily. Defer the update until updates
+                // have been resumed.
+                if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, rotation is paused.");
+                return false;
+            }
+
+            final ScreenRotationAnimation screenRotationAnimation =
+                    mService.mAnimator.getScreenRotationAnimationLocked(displayId);
+            if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
+                // Rotation updates cannot be performed while the previous rotation change animation
+                // is still in progress. Skip this update. We will try updating again after the
+                // animation is finished and the display is unfrozen.
+                if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, animation in progress.");
+                return false;
+            }
+            if (mService.mDisplayFrozen) {
+                // Even if the screen rotation animation has finished (e.g. isAnimating returns
+                // false), there is still some time where we haven't yet unfrozen the display. We
+                // also need to abort rotation here.
+                if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
+                        "Deferring rotation, still finishing previous rotation");
+                return false;
+            }
+        }
+
+        if (!mService.mDisplayEnabled) {
+            // No point choosing a rotation if the display is not enabled.
+            if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, display is not enabled.");
+            return false;
+        }
+
+        final int oldRotation = mRotation;
+        final int lastOrientation = mLastOrientation;
+        final int rotation = rotationForOrientation(lastOrientation, oldRotation);
+        if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Computed rotation=" + rotation + " for display id="
+                + displayId + " based on lastOrientation=" + lastOrientation
+                + " and oldRotation=" + oldRotation);
+
+        if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + displayId
+                + " selected orientation " + lastOrientation
+                + ", got rotation " + rotation);
+
+        if (oldRotation == rotation) {
+            // No change.
+            return false;
+        }
+
+        if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + displayId
+                + " rotation changed to " + rotation
+                + " from " + oldRotation
+                + ", lastOrientation=" + lastOrientation);
+
+        if (DisplayContent.deltaRotation(rotation, oldRotation) != 2) {
+            mDisplayContent.mWaitingForConfig = true;
+        }
+
+        mRotation = rotation;
+
+        mService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
+        mService.mH.sendNewMessageDelayed(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT,
+                mDisplayContent, WINDOW_FREEZE_TIMEOUT_DURATION);
+
+        mDisplayContent.setLayoutNeeded();
+
+        if (shouldRotateSeamlessly(oldRotation, rotation, forceUpdate)) {
+            // The screen rotation animation uses a screenshot to freeze the screen while windows
+            // resize underneath. When we are rotating seamlessly, we allow the elements to
+            // transition to their rotated state independently and without a freeze required.
+            prepareSeamlessRotation();
+        } else {
+            prepareNormalRotationAnimation();
+        }
+
+        return true;
+    }
+
+    void prepareNormalRotationAnimation() {
+        final RotationAnimationPair anim = selectRotationAnimation();
+        mService.startFreezingDisplayLocked(anim.mExit, anim.mEnter, mDisplayContent);
+    }
+
+    private void prepareSeamlessRotation() {
+        // We are careful to reset this in case a window was removed before it finished
+        // seamless rotation.
+        mSeamlessRotationCount = 0;
+        mRotatingSeamlessly = true;
+    }
+
+    boolean isRotatingSeamlessly() {
+        return mRotatingSeamlessly;
+    }
+
+    @VisibleForTesting
+    boolean shouldRotateSeamlessly(int oldRotation, int newRotation, boolean forceUpdate) {
+        final WindowState w = mDisplayPolicy.getTopFullscreenOpaqueWindow();
+        if (w == null || w != mDisplayContent.mCurrentFocus) {
+            return false;
+        }
+        // We only enable seamless rotation if the top window has requested it and is in the
+        // fullscreen opaque state. Seamless rotation requires freezing various Surface states and
+        // won't work well with animations, so we disable it in the animation case for now.
+        if (w.getAttrs().rotationAnimation != ROTATION_ANIMATION_SEAMLESS || w.isAnimatingLw()) {
+            return false;
+        }
+
+        // For the upside down rotation we don't rotate seamlessly as the navigation bar moves
+        // position. Note most apps (using orientation:sensor or user as opposed to fullSensor)
+        // will not enter the reverse portrait orientation, so actually the orientation won't change
+        // at all.
+        if (oldRotation == mUpsideDownRotation || newRotation == mUpsideDownRotation) {
+            return false;
+        }
+
+        // If the navigation bar can't change sides, then it will jump when we change orientations
+        // and we don't rotate seamlessly - unless that is allowed, eg. with gesture navigation
+        // where the navbar is low-profile enough that this isn't very noticeable.
+        if (!mAllowSeamlessRotationDespiteNavBarMoving && !mDisplayPolicy.navigationBarCanMove()) {
+            return false;
+        }
+
+        // If the bounds of activity window is different from its parent, then reject to be seamless
+        // because the window position may change after rotation that will look like a sudden jump.
+        if (w.mAppToken != null && !w.mAppToken.matchParentBounds()) {
+            return false;
+        }
+
+        // In the presence of the PINNED stack or System Alert windows we unfortunately can not
+        // seamlessly rotate.
+        if (mDisplayContent.hasPinnedStack() || mDisplayContent.hasAlertWindowSurfaces()) {
+            return false;
+        }
+
+        // We can't rotate (seamlessly or not) while waiting for the last seamless rotation to
+        // complete (that is, waiting for windows to redraw). It's tempting to check
+        // mSeamlessRotationCount but that could be incorrect in the case of window-removal.
+        if (!forceUpdate && mDisplayContent.getWindow(win -> win.mSeamlesslyRotated) != null) {
+            return false;
+        }
+
+        return true;
+    }
+
+    void markForSeamlessRotation(WindowState w, boolean seamlesslyRotated) {
+        if (seamlesslyRotated == w.mSeamlesslyRotated || w.mForceSeamlesslyRotate) {
+            return;
+        }
+
+        w.mSeamlesslyRotated = seamlesslyRotated;
+        if (seamlesslyRotated) {
+            mSeamlessRotationCount++;
+        } else {
+            mSeamlessRotationCount--;
+        }
+        if (mSeamlessRotationCount == 0) {
+            if (DEBUG_ORIENTATION) {
+                Slog.i(TAG, "Performing post-rotate rotation after seamless rotation");
+            }
+            // Finish seamless rotation.
+            mRotatingSeamlessly = false;
+
+            updateRotationAndSendNewConfigIfChanged();
+        }
+    }
+
+    void onSeamlessRotationTimeout() {
+        final boolean[] isLayoutNeeded = { false };
+
+        mDisplayContent.forAllWindows(w -> {
+            if (!w.mSeamlesslyRotated) {
+                return;
+            }
+            isLayoutNeeded[0] = true;
+            w.setDisplayLayoutNeeded();
+            w.finishSeamlessRotation(true /* timeout */);
+            markForSeamlessRotation(w, false /* seamlesslyRotated */);
+        }, true /* traverseTopToBottom */);
+
+        if (isLayoutNeeded[0]) {
+            mService.mWindowPlacerLocked.performSurfacePlacement();
+        }
+    }
+
+    /**
+     * Returns the animation to run for a rotation transition based on the top fullscreen windows
+     * {@link android.view.WindowManager.LayoutParams#rotationAnimation} and whether it is currently
+     * fullscreen and frontmost.
+     */
+    private RotationAnimationPair selectRotationAnimation() {
+        // If the screen is off or non-interactive, force a jumpcut.
+        final boolean forceJumpcut = !mDisplayPolicy.isScreenOnFully()
+                || !mService.mPolicy.okToAnimate();
+        final WindowState topFullscreen = mDisplayPolicy.getTopFullscreenOpaqueWindow();
+        if (DEBUG_ANIM) Slog.i(TAG, "selectRotationAnimation topFullscreen="
+                + topFullscreen + " rotationAnimation="
+                + (topFullscreen == null ? 0 : topFullscreen.getAttrs().rotationAnimation)
+                + " forceJumpcut=" + forceJumpcut);
+        if (forceJumpcut) {
+            mTmpRotationAnim.mExit = R.anim.rotation_animation_jump_exit;
+            mTmpRotationAnim.mEnter = R.anim.rotation_animation_enter;
+            return mTmpRotationAnim;
+        }
+        if (topFullscreen != null) {
+            int animationHint = topFullscreen.getRotationAnimationHint();
+            if (animationHint < 0 && mDisplayPolicy.isTopLayoutFullscreen()) {
+                animationHint = topFullscreen.getAttrs().rotationAnimation;
+            }
+            switch (animationHint) {
+                case ROTATION_ANIMATION_CROSSFADE:
+                case ROTATION_ANIMATION_SEAMLESS: // Crossfade is fallback for seamless.
+                    mTmpRotationAnim.mExit = R.anim.rotation_animation_xfade_exit;
+                    mTmpRotationAnim.mEnter = R.anim.rotation_animation_enter;
+                    break;
+                case ROTATION_ANIMATION_JUMPCUT:
+                    mTmpRotationAnim.mExit = R.anim.rotation_animation_jump_exit;
+                    mTmpRotationAnim.mEnter = R.anim.rotation_animation_enter;
+                    break;
+                case ROTATION_ANIMATION_ROTATE:
+                default:
+                    mTmpRotationAnim.mExit = mTmpRotationAnim.mEnter = 0;
+                    break;
+            }
+        } else {
+            mTmpRotationAnim.mExit = mTmpRotationAnim.mEnter = 0;
+        }
+        return mTmpRotationAnim;
+    }
+
+    /**
+     * Validate whether the current top fullscreen has specified the same
+     * {@link android.view.WindowManager.LayoutParams#rotationAnimation} value as that being passed
+     * in from the previous top fullscreen window.
+     *
+     * @param exitAnimId exiting resource id from the previous window.
+     * @param enterAnimId entering resource id from the previous window.
+     * @param forceDefault For rotation animations only, if true ignore the animation values and
+     *                     just return false.
+     * @return {@code true} if the previous values are still valid, false if they should be replaced
+     *         with the default.
+     */
+    boolean validateRotationAnimation(int exitAnimId, int enterAnimId, boolean forceDefault) {
+        switch (exitAnimId) {
+            case R.anim.rotation_animation_xfade_exit:
+            case R.anim.rotation_animation_jump_exit:
+                // These are the only cases that matter.
+                if (forceDefault) {
+                    return false;
+                }
+                final RotationAnimationPair anim = selectRotationAnimation();
+                return exitAnimId == anim.mExit && enterAnimId == anim.mEnter;
+            default:
+                return true;
+        }
     }
 
     void restoreSettings(int userRotationMode, int userRotation,
@@ -327,7 +717,7 @@
     }
 
     void freezeRotation(int rotation) {
-        rotation = (rotation == -1) ? mDisplayContent.getRotation() : rotation;
+        rotation = (rotation == -1) ? mRotation : rotation;
         setUserRotation(WindowManagerPolicy.USER_ROTATION_LOCKED, rotation);
     }
 
@@ -407,6 +797,30 @@
     }
 
     /**
+     * Temporarily pauses rotation changes until resumed.
+     * <p>
+     * This can be used to prevent rotation changes from occurring while the user is performing
+     * certain operations, such as drag and drop.
+     * <p>
+     * This call nests and must be matched by an equal number of calls to {@link #resume}.
+     */
+    void pause() {
+        mDeferredRotationPauseCount++;
+    }
+
+    /** Resumes normal rotation changes after being paused. */
+    void resume() {
+        if (mDeferredRotationPauseCount <= 0) {
+            return;
+        }
+
+        mDeferredRotationPauseCount--;
+        if (mDeferredRotationPauseCount == 0) {
+            updateRotationAndSendNewConfigIfChanged();
+        }
+    }
+
+    /**
      * Various use cases for invoking this function:
      * <li>Screen turning off, should always disable listeners if already enabled.</li>
      * <li>Screen turned on and current app has sensor based orientation, enable listeners
@@ -515,14 +929,28 @@
     }
 
     /**
-     * Given an orientation constant, returns the appropriate surface rotation,
-     * taking into account sensors, docking mode, rotation lock, and other factors.
+     * If this is true we have updated our desired orientation, but not yet changed the real
+     * orientation our applied our screen rotation animation. For example, because a previous
+     * screen rotation was in progress.
+     *
+     * @return {@code true} if the there is an ongoing rotation change.
+     */
+    boolean needsUpdate() {
+        final int oldRotation = mRotation;
+        final int rotation = rotationForOrientation(mLastOrientation, oldRotation);
+        return oldRotation != rotation;
+    }
+
+    /**
+     * Given an orientation constant, returns the appropriate surface rotation, taking into account
+     * sensors, docking mode, rotation lock, and other factors.
      *
      * @param orientation An orientation constant, such as
-     * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}.
+     *                    {@link ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}.
      * @param lastRotation The most recently used rotation.
      * @return The surface rotation to use.
      */
+    @VisibleForTesting
     int rotationForOrientation(int orientation, int lastRotation) {
         if (DEBUG_ORIENTATION) {
             Slog.v(TAG, "rotationForOrientation(orient="
@@ -614,15 +1042,16 @@
                 || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT) {
             // Otherwise, use sensor only if requested by the application or enabled
             // by default for USER or UNSPECIFIED modes.  Does not apply to NOSENSOR.
-            if (mAllowAllRotations < 0) {
-                // Can't read this during init() because the context doesn't
-                // have display metrics at that time so we cannot determine
-                // tablet vs. phone then.
+            if (mAllowAllRotations == ALLOW_ALL_ROTATIONS_UNDEFINED) {
+                // Can't read this during init() because the context doesn't have display metrics at
+                // that time so we cannot determine tablet vs. phone then.
                 mAllowAllRotations = mContext.getResources().getBoolean(
-                        com.android.internal.R.bool.config_allowAllRotations) ? 1 : 0;
+                        R.bool.config_allowAllRotations)
+                                ? ALLOW_ALL_ROTATIONS_ENABLED
+                                : ALLOW_ALL_ROTATIONS_DISABLED;
             }
             if (sensorRotation != Surface.ROTATION_180
-                    || mAllowAllRotations == 1
+                    || mAllowAllRotations == ALLOW_ALL_ROTATIONS_ENABLED
                     || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
                     || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER) {
                 preferredRotation = sensorRotation;
@@ -883,6 +1312,10 @@
         pw.println(prefix + "DisplayRotation");
         pw.println(prefix + "  mCurrentAppOrientation="
                 + ActivityInfo.screenOrientationToString(mCurrentAppOrientation));
+        pw.println(prefix + "  mLastOrientation=" + mLastOrientation);
+        pw.print(prefix + "  mRotation=" + mRotation);
+        pw.println(" mDeferredRotationPauseCount=" + mDeferredRotationPauseCount);
+
         pw.print(prefix + "  mLandscapeRotation=" + Surface.rotationToString(mLandscapeRotation));
         pw.println(" mSeascapeRotation=" + Surface.rotationToString(mSeascapeRotation));
         pw.print(prefix + "  mPortraitRotation=" + Surface.rotationToString(mPortraitRotation));
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index c8f7af5..c48f07c 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -305,7 +305,7 @@
             if (DEBUG_ORIENTATION) {
                 Slog.d(TAG_WM, "Pausing rotation during drag");
             }
-            mDisplayContent.pauseRotationLocked();
+            mDisplayContent.getDisplayRotation().pause();
         }
 
         void tearDown() {
@@ -324,7 +324,7 @@
             if (DEBUG_ORIENTATION) {
                 Slog.d(TAG_WM, "Resuming rotation after drag");
             }
-            mDisplayContent.resumeRotationLocked();
+            mDisplayContent.getDisplayRotation().resume();
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 402ec59..b7835aa 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -106,6 +106,11 @@
             @Nullable TriConsumer<DisplayFrames, WindowState, Rect> frameProvider) {
         if (mWin != null) {
             mWin.setInsetProvider(null);
+            // The window may be animating such that we can hand out the leash to the control
+            // target. Revoke the leash by cancelling the animation to correct the state.
+            // TODO: Ideally, we should wait for the animation to finish so previous window can
+            // animate-out as new one animates-in.
+            mWin.cancelAnimation();
         }
         mWin = win;
         mFrameProvider = frameProvider;
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index 3401de6..eb5d096 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -636,7 +636,7 @@
         final DisplayContent displayContent = mRootWindowContainer.getDisplayContent(displayId);
         Configuration config = null;
         if (displayContent != null) {
-            config = displayContent.updateOrientationFromAppTokens(
+            config = displayContent.updateOrientation(
                     getDisplayOverrideConfiguration(displayId),
                     starting != null && starting.mayFreezeScreenLocked(starting.app)
                             ? starting.appToken : null,
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index a00bee0..968d02b 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -925,8 +925,7 @@
     boolean updateRotationUnchecked() {
         boolean changed = false;
         for (int i = mChildren.size() - 1; i >= 0; i--) {
-            final DisplayContent displayContent = mChildren.get(i);
-            if (displayContent.updateRotationAndSendNewConfigIfNeeded()) {
+            if (mChildren.get(i).getDisplayRotation().updateRotationAndSendNewConfigIfChanged()) {
                 changed = true;
             }
         }
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 9f8f265..4a76042 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -40,6 +40,7 @@
 import android.os.RemoteException;
 import android.os.Trace;
 import android.os.UserHandle;
+import android.util.ArraySet;
 import android.util.MergedConfiguration;
 import android.util.Slog;
 import android.view.DisplayCutout;
@@ -57,9 +58,7 @@
 import com.android.server.wm.WindowManagerService.H;
 
 import java.io.PrintWriter;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
 import java.util.function.BiConsumer;
 
 /**
@@ -75,9 +74,9 @@
     SurfaceSession mSurfaceSession;
     private int mNumWindow = 0;
     // Set of visible application overlay window surfaces connected to this session.
-    private final Set<WindowSurfaceController> mAppOverlaySurfaces = new HashSet<>();
+    private final ArraySet<WindowSurfaceController> mAppOverlaySurfaces = new ArraySet<>();
     // Set of visible alert window surfaces connected to this session.
-    private final Set<WindowSurfaceController> mAlertWindowSurfaces = new HashSet<>();
+    private final ArraySet<WindowSurfaceController> mAlertWindowSurfaces = new ArraySet<>();
     private final DragDropController mDragDropController;
     final boolean mCanAddInternalSystemWindow;
     final boolean mCanHideNonSystemOverlayWindows;
@@ -609,8 +608,15 @@
         return mStringName;
     }
 
-    boolean hasAlertWindowSurfaces() {
-        return !mAlertWindowSurfaces.isEmpty();
+    /** @return {@code true} if there is an alert window surface on the given display. */
+    boolean hasAlertWindowSurfaces(DisplayContent displayContent) {
+        for (int i = mAlertWindowSurfaces.size() - 1; i >= 0; i--) {
+            final WindowSurfaceController surfaceController = mAlertWindowSurfaces.valueAt(i);
+            if (surfaceController.mAnimator.mWin.getDisplayContent() == displayContent) {
+                return true;
+            }
+        }
+        return false;
     }
 
     public void blessInputSurface(int displayId, SurfaceControl surface,
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 2fc64ea..8b0b6ce 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -304,7 +304,7 @@
         if (DEBUG_ORIENTATION) {
             Slog.d(TAG, "Pausing rotation during re-position");
         }
-        mDisplayContent.pauseRotationLocked();
+        mDisplayContent.getDisplayRotation().pause();
 
         // Notify InputMonitor to take mDragWindowHandle.
         mDisplayContent.getInputMonitor().updateInputWindowsLw(true /*force*/);
@@ -347,7 +347,7 @@
         if (DEBUG_ORIENTATION) {
             Slog.d(TAG, "Resuming rotation after re-position");
         }
-        mDisplayContent.resumeRotationLocked();
+        mDisplayContent.getDisplayRotation().resume();
         mDisplayContent = null;
         mClientCallback.unlinkToDeath(this, 0 /* flags */);
     }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b25677a..d49d245 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -141,7 +141,6 @@
 import android.graphics.Bitmap;
 import android.graphics.Insets;
 import android.graphics.Matrix;
-import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.RectF;
@@ -667,19 +666,6 @@
     WindowManagerInternal.OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener;
     SettingsObserver mSettingsObserver;
 
-    /**
-     * A count of the windows which are 'seamlessly rotated', e.g. a surface
-     * at an old orientation is being transformed. We freeze orientation updates
-     * while any windows are seamlessly rotated, so we need to track when this
-     * hits zero so we can apply deferred orientation updates.
-     */
-    private int mSeamlessRotationCount = 0;
-    /**
-     * True in the interval from starting seamless rotation until the last rotated
-     * window draws in the new orientation.
-     */
-    private boolean mRotatingSeamlessly = false;
-
     private final class SettingsObserver extends ContentObserver {
         private final Uri mDisplayInversionEnabledUri =
                 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
@@ -1247,7 +1233,6 @@
             return res;
         }
 
-        boolean reportNewConfig = false;
         WindowState parentWindow = null;
         long origId;
         final int callingUid = Binder.getCallingUid();
@@ -1623,11 +1608,7 @@
             if (localLOGV || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addWindow: New client "
                     + client.asBinder() + ": window=" + win + " Callers=" + Debug.getCallers(5));
 
-            if (win.isVisibleOrAdding() && displayContent.updateOrientationFromAppTokens()) {
-                reportNewConfig = true;
-            }
-
-            if (reportNewConfig) {
+            if (win.isVisibleOrAdding() && displayContent.updateOrientation()) {
                 displayContent.sendNewConfiguration();
             }
         }
@@ -1791,11 +1772,11 @@
         if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "postWindowRemoveCleanupLocked: " + win);
         mWindowMap.remove(win.mClient.asBinder());
 
-        markForSeamlessRotation(win, false);
+        final DisplayContent dc = win.getDisplayContent();
+        dc.getDisplayRotation().markForSeamlessRotation(win, false /* seamlesslyRotated */);
 
         win.resetAppOpsState();
 
-        final DisplayContent dc = win.getDisplayContent();
         if (dc.mCurrentFocus == null) {
             dc.mWinRemovedSinceNullFocus.add(win);
         }
@@ -2241,9 +2222,8 @@
                 displayContent.mUnknownAppVisibilityController.notifyRelayouted(win.mAppToken);
             }
 
-            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
-                    "relayoutWindow: updateOrientationFromAppTokens");
-            configChanged = displayContent.updateOrientationFromAppTokens();
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: updateOrientation");
+            configChanged = displayContent.updateOrientation();
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
 
             if (toBeDisplayed && win.mIsWallpaper) {
@@ -4859,7 +4839,7 @@
                 case SEAMLESS_ROTATION_TIMEOUT: {
                     final DisplayContent displayContent = (DisplayContent) msg.obj;
                     synchronized (mGlobalLock) {
-                        displayContent.onSeamlessRotationTimeout();
+                        displayContent.getDisplayRotation().onSeamlessRotationTimeout();
                     }
                     break;
                 }
@@ -5321,7 +5301,7 @@
 
     void startFreezingDisplayLocked(int exitAnim, int enterAnim,
             DisplayContent displayContent) {
-        if (mDisplayFrozen || mRotatingSeamlessly) {
+        if (mDisplayFrozen || displayContent.getDisplayRotation().isRotatingSeamlessly()) {
             return;
         }
 
@@ -5430,8 +5410,8 @@
             if (DEBUG_ORIENTATION) Slog.i(TAG_WM, "**** Dismissing screen rotation animation");
             DisplayInfo displayInfo = displayContent.getDisplayInfo();
             // Get rotation animation again, with new top window
-            if (!displayContent.getDisplayPolicy()
-                    .validateRotationAnimationLw(mExitAnimId, mEnterAnimId, false)) {
+            if (!displayContent.getDisplayRotation().validateRotationAnimation(
+                    mExitAnimId, mEnterAnimId, false /* forceDefault */)) {
                 mExitAnimId = mEnterAnimId = 0;
             }
             if (screenRotationAnimation.dismiss(mTransaction, MAX_ANIMATION_DURATION,
@@ -5458,7 +5438,7 @@
         // to avoid inconsistent states.  However, something interesting
         // could have actually changed during that time so re-evaluate it
         // now to catch that.
-        configChanged = displayContent != null && displayContent.updateOrientationFromAppTokens();
+        configChanged = displayContent != null && displayContent.updateOrientation();
 
         // A little kludge: a lot could have happened while the
         // display was frozen, so now that we are coming back we
@@ -6984,26 +6964,6 @@
         mPolicy.requestUserActivityNotification();
     }
 
-    void markForSeamlessRotation(WindowState w, boolean seamlesslyRotated) {
-        if (seamlesslyRotated == w.mSeamlesslyRotated || w.mForceSeamlesslyRotate) {
-            return;
-        }
-        w.mSeamlesslyRotated = seamlesslyRotated;
-        if (seamlesslyRotated) {
-            mSeamlessRotationCount++;
-        } else {
-            mSeamlessRotationCount--;
-        }
-        if (mSeamlessRotationCount == 0) {
-            if (DEBUG_ORIENTATION) {
-                Slog.i(TAG, "Performing post-rotate rotation after seamless rotation");
-            }
-            finishSeamlessRotation();
-
-            w.getDisplayContent().updateRotationAndSendNewConfigIfNeeded();
-        }
-    }
-
     private final class LocalService extends WindowManagerInternal {
         @Override
         public void requestTraversalFromDisplayManager() {
@@ -7531,22 +7491,6 @@
         return mSurfaceBuilderFactory.make(s);
     }
 
-    void startSeamlessRotation() {
-        // We are careful to reset this in case a window was removed before it finished
-        // seamless rotation.
-        mSeamlessRotationCount = 0;
-
-        mRotatingSeamlessly = true;
-    }
-
-    boolean isRotatingSeamlessly() {
-        return mRotatingSeamlessly;
-    }
-
-    void finishSeamlessRotation() {
-        mRotatingSeamlessly = false;
-    }
-
     /**
      * Called when the state of lock task mode changes. This should be used to disable immersive
      * mode confirmation.
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index d87a0ed..4900869 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -652,7 +652,8 @@
         if (mForceSeamlesslyRotate || requested) {
             mPendingSeamlessRotate = new SeamlessRotator(oldRotation, rotation, getDisplayInfo());
             mPendingSeamlessRotate.unrotate(transaction, this);
-            mWmService.markForSeamlessRotation(this, true);
+            getDisplayContent().getDisplayRotation().markForSeamlessRotation(this,
+                    true /* seamlesslyRotated */);
         }
     }
 
@@ -661,7 +662,8 @@
             mPendingSeamlessRotate.finish(this, timeout);
             mFinishSeamlessRotateFrameNumber = getFrameNumber();
             mPendingSeamlessRotate = null;
-            mWmService.markForSeamlessRotation(this, false);
+            getDisplayContent().getDisplayRotation().markForSeamlessRotation(this,
+                    false /* seamlesslyRotated */);
         }
     }
 
@@ -2086,7 +2088,7 @@
             // So just update orientation if needed.
             if (wasVisible) {
                 final DisplayContent displayContent = getDisplayContent();
-                if (displayContent.updateOrientationFromAppTokens()) {
+                if (displayContent.updateOrientation()) {
                     displayContent.sendNewConfiguration();
                 }
             }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index f933b09..478bc88 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -248,6 +248,7 @@
 import com.android.internal.util.StatLogger;
 import com.android.internal.util.XmlUtils;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockSettingsInternal;
 import com.android.server.LocalServices;
 import com.android.server.LockGuard;
 import com.android.server.SystemServerInitThreadPool;
@@ -500,6 +501,7 @@
     final UsageStatsManagerInternal mUsageStatsManagerInternal;
     final TelephonyManager mTelephonyManager;
     private final LockPatternUtils mLockPatternUtils;
+    private final LockSettingsInternal mLockSettingsInternal;
     private final DeviceAdminServiceController mDeviceAdminServiceController;
     private final OverlayPackagesProvider mOverlayPackagesProvider;
 
@@ -739,7 +741,6 @@
     final SparseArray<DevicePolicyData> mUserData = new SparseArray<>();
 
     @GuardedBy("getLockObject()")
-    final SparseArray<PasswordMetrics> mUserPasswordMetrics = new SparseArray<>();
 
     final Handler mHandler;
     final Handler mBackgroundHandler;
@@ -1994,6 +1995,10 @@
             return IAudioService.Stub.asInterface(ServiceManager.getService(Context.AUDIO_SERVICE));
         }
 
+        LockSettingsInternal getLockSettingsInternal() {
+            return LocalServices.getService(LockSettingsInternal.class);
+        }
+
         boolean isBuildDebuggable() {
             return Build.IS_DEBUGGABLE;
         }
@@ -2233,7 +2238,7 @@
 
         mLocalService = new LocalService();
         mLockPatternUtils = injector.newLockPatternUtils();
-
+        mLockSettingsInternal = injector.getLockSettingsInternal();
         // TODO: why does SecurityLogMonitor need to be created even when mHasFeature == false?
         mSecurityLogMonitor = new SecurityLogMonitor(this);
 
@@ -2309,17 +2314,6 @@
     }
 
     /**
-     * Provides PasswordMetrics object corresponding to the given user.
-     * @param userHandle the user for whom to provide metrics.
-     * @return the user password metrics, or {@code null} if none have been associated with
-     * the user yet (for example, if the device has booted but not been unlocked).
-     */
-    @GuardedBy("getLockObject()")
-    PasswordMetrics getUserPasswordMetricsLocked(int userHandle) {
-        return mUserPasswordMetrics.get(userHandle);
-    }
-
-    /**
      * Creates and loads the policy data from xml for data that is shared between
      * various profiles of a user. In contrast to {@link #getUserData(int)}
      * it allows access to data of users other than the calling user.
@@ -2353,9 +2347,6 @@
             if (policy != null) {
                 mUserData.remove(userHandle);
             }
-            if (mUserPasswordMetrics.get(userHandle) != null) {
-                mUserPasswordMetrics.remove(userHandle);
-            }
 
             File policyFile = new File(mInjector.environmentGetUserSystemDirectory(userHandle),
                     DEVICE_POLICIES_XML);
@@ -4183,15 +4174,16 @@
     private void updatePasswordValidityCheckpointLocked(int userHandle, boolean parent) {
         final int credentialOwner = getCredentialOwner(userHandle, parent);
         DevicePolicyData policy = getUserData(credentialOwner);
-        PasswordMetrics metrics = getUserPasswordMetricsLocked(credentialOwner);
-        if (metrics == null) {
-            metrics = new PasswordMetrics();
+        PasswordMetrics metrics = mLockSettingsInternal.getUserPasswordMetrics(credentialOwner);
+        // Update the checkpoint only if the user's password metrics is known
+        if (metrics != null) {
+            final boolean newCheckpoint = isPasswordSufficientForUserWithoutCheckpointLocked(
+                    metrics, userHandle, parent);
+            if (newCheckpoint != policy.mPasswordValidAtLastCheckpoint) {
+                policy.mPasswordValidAtLastCheckpoint = newCheckpoint;
+                saveSettingsLocked(credentialOwner);
+            }
         }
-        policy.mPasswordValidAtLastCheckpoint =
-                isPasswordSufficientForUserWithoutCheckpointLocked(
-                        metrics, userHandle, parent);
-
-        saveSettingsLocked(credentialOwner);
     }
 
     /**
@@ -4766,7 +4758,7 @@
             getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
             int credentialOwner = getCredentialOwner(userHandle, parent);
             DevicePolicyData policy = getUserDataUnchecked(credentialOwner);
-            PasswordMetrics metrics = getUserPasswordMetricsLocked(credentialOwner);
+            PasswordMetrics metrics = mLockSettingsInternal.getUserPasswordMetrics(credentialOwner);
             return isActivePasswordSufficientForUserLocked(
                     policy.mPasswordValidAtLastCheckpoint, metrics, userHandle, parent);
         }
@@ -4796,15 +4788,15 @@
             enforceUserUnlocked(targetUser, false);
             int credentialOwner = getCredentialOwner(userHandle, false);
             DevicePolicyData policy = getUserDataUnchecked(credentialOwner);
-            PasswordMetrics metrics = getUserPasswordMetricsLocked(credentialOwner);
+            PasswordMetrics metrics = mLockSettingsInternal.getUserPasswordMetrics(credentialOwner);
             return isActivePasswordSufficientForUserLocked(
                     policy.mPasswordValidAtLastCheckpoint, metrics, targetUser, false);
         }
     }
 
     private boolean isActivePasswordSufficientForUserLocked(
-            boolean passwordValidAtLastCheckpoint, PasswordMetrics metrics, int userHandle,
-            boolean parent) {
+            boolean passwordValidAtLastCheckpoint, @Nullable PasswordMetrics metrics,
+            int userHandle, boolean parent) {
         if (!mInjector.storageManagerIsFileBasedEncryptionEnabled() && (metrics == null)) {
             // Before user enters their password for the first time after a reboot, return the
             // value of this flag, which tells us whether the password was valid the last time
@@ -4815,9 +4807,10 @@
         }
 
         if (metrics == null) {
-            // This could happen if the user never had a password set, for example, so
-            // setActivePasswordState has never been called for it.
-            metrics = new PasswordMetrics();
+            // Called on a FBE device when the user password exists but its metrics is unknown.
+            // This shouldn't happen since we enforce the user to be unlocked (which would result
+            // in the metrics known to the framework on a FBE device) at all call sites.
+            throw new IllegalStateException("isActivePasswordSufficient called on FBE-locked user");
         }
 
         return isPasswordSufficientForUserWithoutCheckpointLocked(metrics, userHandle, parent);
@@ -4829,7 +4822,7 @@
      * {@code userId} (or its parent, if {@code parent} is set to {@code true}).
      */
     private boolean isPasswordSufficientForUserWithoutCheckpointLocked(
-            PasswordMetrics metrics, @UserIdInt int userId, boolean parent) {
+            @NonNull PasswordMetrics metrics, @UserIdInt int userId, boolean parent) {
         final int requiredQuality = getPasswordQuality(null, userId, parent);
 
         if (requiredQuality >= PASSWORD_QUALITY_NUMERIC
@@ -4867,7 +4860,7 @@
 
         synchronized (getLockObject()) {
             int targetUserId = getCredentialOwner(callingUserId, /* parent= */ false);
-            PasswordMetrics metrics = getUserPasswordMetricsLocked(targetUserId);
+            PasswordMetrics metrics = mLockSettingsInternal.getUserPasswordMetrics(targetUserId);
             return metrics == null ? PASSWORD_COMPLEXITY_NONE : metrics.determineComplexity();
         }
     }
@@ -6707,31 +6700,6 @@
         }
     }
 
-    /**
-     * Notify DPMS regarding the metric of the current password. This happens when the user changes
-     * the password, but also when the user just unlocks the keyguard. In comparison,
-     * reportPasswordChanged() is only called when the user changes the password.
-     */
-    @Override
-    public void setActivePasswordState(PasswordMetrics metrics, int userHandle) {
-        if (!mLockPatternUtils.hasSecureLockScreen()) {
-            return;
-        }
-        enforceFullCrossUsersPermission(userHandle);
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.BIND_DEVICE_ADMIN, null);
-
-        // If the managed profile doesn't have a separate password, set the metrics to default
-        if (isManagedProfile(userHandle) && !isSeparateProfileChallengeEnabled(userHandle)) {
-            metrics = new PasswordMetrics();
-        }
-
-        validateQualityConstant(metrics.quality);
-        synchronized (getLockObject()) {
-            mUserPasswordMetrics.put(userHandle, metrics);
-        }
-    }
-
     @Override
     public void reportPasswordChanged(@UserIdInt int userId) {
         if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
diff --git a/services/net/Android.bp b/services/net/Android.bp
index fb548f9..8f8f9f9 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -67,7 +67,7 @@
     static_libs: [
         "dnsresolver_aidl_interface-V2-java",
         "ipmemorystore-client",
-        "netd_aidl_interface-V2-java",
+        "netd_aidl_interface-java",
         "networkstack-aidl-interfaces-V3-java",
     ],
 }
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
index 274ca36..104aacb 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
@@ -16,15 +16,18 @@
 
 package com.android.server.accessibility.gestures;
 
+import static com.android.server.accessibility.gestures.TouchState.STATE_CLEAR;
+import static com.android.server.accessibility.gestures.TouchState.STATE_DELEGATING;
+import static com.android.server.accessibility.gestures.TouchState.STATE_DRAGGING;
+import static com.android.server.accessibility.gestures.TouchState.STATE_TOUCH_EXPLORING;
+
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 
 import android.content.Context;
 import android.graphics.PointF;
 import android.os.SystemClock;
 import android.testing.DexmakerShareClassLoaderRule;
-import android.util.DebugUtils;
 import android.view.InputDevice;
 import android.view.MotionEvent;
 
@@ -46,10 +49,6 @@
 @RunWith(AndroidJUnit4.class)
 public class TouchExplorerTest {
 
-    public static final int STATE_TOUCH_EXPLORING = 0x00000001;
-    public static final int STATE_DRAGGING = 0x00000002;
-    public static final int STATE_DELEGATING = 0x00000004;
-
     private static final int FLAG_1FINGER = 0x8000;
     private static final int FLAG_2FINGERS = 0x0100;
     private static final int FLAG_3FINGERS = 0x0200;
@@ -112,7 +111,7 @@
 
     @Test
     public void testTwoFingersMove_shouldDelegatingAndInjectActionDownPointerDown() {
-        goFromStateIdleTo(STATE_MOVING_2FINGERS);
+        goFromStateClearTo(STATE_MOVING_2FINGERS);
 
         assertState(STATE_DELEGATING);
         assertCapturedEvents(
@@ -123,7 +122,7 @@
 
     @Test
     public void testTwoFingersDrag_shouldDraggingAndActionDown() {
-        goFromStateIdleTo(STATE_DRAGGING_2FINGERS);
+        goFromStateClearTo(STATE_DRAGGING_2FINGERS);
 
         assertState(STATE_DRAGGING);
         assertCapturedEvents(MotionEvent.ACTION_DOWN);
@@ -133,7 +132,7 @@
     @Test
     public void testTwoFingersNotDrag_shouldDelegatingAndActionUpDownPointerDown() {
         // only from dragging state, and withMoveHistory no dragging
-        goFromStateIdleTo(STATE_PINCH_2FINGERS);
+        goFromStateClearTo(STATE_PINCH_2FINGERS);
 
         assertState(STATE_DELEGATING);
         assertCapturedEvents(
@@ -146,7 +145,7 @@
 
     @Test
     public void testThreeFingersMove_shouldDelegatingAnd3ActionPointerDown() {
-        goFromStateIdleTo(STATE_MOVING_3FINGERS);
+        goFromStateClearTo(STATE_MOVING_3FINGERS);
 
         assertState(STATE_DELEGATING);
         assertCapturedEvents(
@@ -165,52 +164,47 @@
         return new PointF(x, y);
     }
 
-    private static String stateToString(int state) {
-        return DebugUtils.valueToString(TouchExplorerTest.class, "STATE_", state);
-    }
-
-    private void goFromStateIdleTo(int state) {
+    private void goFromStateClearTo(int state) {
         try {
             switch (state) {
-                case STATE_TOUCH_EXPLORING: {
+                case STATE_CLEAR: {
                     mTouchExplorer.onDestroy();
                 }
                 break;
                 case STATE_TOUCH_EXPLORING_1FINGER: {
-                    goFromStateIdleTo(STATE_TOUCH_EXPLORING);
                     send(downEvent());
                 }
                 break;
                 case STATE_TOUCH_EXPLORING_2FINGER: {
-                    goFromStateIdleTo(STATE_TOUCH_EXPLORING_1FINGER);
+                    goFromStateClearTo(STATE_TOUCH_EXPLORING_1FINGER);
                     send(pointerDownEvent());
                 }
                 break;
                 case STATE_TOUCH_EXPLORING_3FINGER: {
-                    goFromStateIdleTo(STATE_TOUCH_EXPLORING_2FINGER);
+                    goFromStateClearTo(STATE_TOUCH_EXPLORING_2FINGER);
                     send(thirdPointerDownEvent());
                 }
                 break;
                 case STATE_MOVING_2FINGERS: {
-                    goFromStateIdleTo(STATE_TOUCH_EXPLORING_2FINGER);
+                    goFromStateClearTo(STATE_TOUCH_EXPLORING_2FINGER);
                     moveEachPointers(mLastEvent, p(10, 0), p(5, 10));
                     send(mLastEvent);
                 }
                 break;
                 case STATE_DRAGGING_2FINGERS: {
-                    goFromStateIdleTo(STATE_TOUCH_EXPLORING_2FINGER);
+                    goFromStateClearTo(STATE_TOUCH_EXPLORING_2FINGER);
                     moveEachPointers(mLastEvent, p(10, 0), p(10, 0));
                     send(mLastEvent);
                 }
                 break;
                 case STATE_PINCH_2FINGERS: {
-                    goFromStateIdleTo(STATE_DRAGGING_2FINGERS);
+                    goFromStateClearTo(STATE_DRAGGING_2FINGERS);
                     moveEachPointers(mLastEvent, p(10, 0), p(-10, 1));
                     send(mLastEvent);
                 }
                 break;
                 case STATE_MOVING_3FINGERS: {
-                    goFromStateIdleTo(STATE_TOUCH_EXPLORING_3FINGER);
+                    goFromStateClearTo(STATE_TOUCH_EXPLORING_3FINGER);
                     moveEachPointers(mLastEvent, p(1, 0), p(1, 0), p(1, 0));
                     send(mLastEvent);
                 }
@@ -219,7 +213,8 @@
                     throw new IllegalArgumentException("Illegal state: " + state);
             }
         } catch (Throwable t) {
-            throw new RuntimeException("Failed to go to state " + stateToString(state), t);
+            throw new RuntimeException("Failed to go to state "
+            + TouchState.getStateSymbolicName(state), t);
         }
     }
 
@@ -234,9 +229,9 @@
     }
 
     private void assertState(int expect) {
-        final String expectState = "STATE_" + stateToString(expect);
-        assertTrue(String.format("Expect state: %s, but: %s", expectState, mTouchExplorer),
-                mTouchExplorer.toString().contains(expectState));
+        assertEquals(
+                TouchState.getStateSymbolicName(expect),
+                TouchState.getStateSymbolicName(mTouchExplorer.getState().getState()));
     }
 
     private void assertCapturedEvents(int... actionsInOrder) {
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 ce83df7..64ea59d 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -48,6 +48,7 @@
 
 import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockSettingsInternal;
 import com.android.server.net.NetworkPolicyManagerInternal;
 
 import java.io.File;
@@ -210,6 +211,11 @@
         }
 
         @Override
+        LockSettingsInternal getLockSettingsInternal() {
+            return services.lockSettingsInternal;
+        }
+
+        @Override
         IAudioService getIAudioService() {
             return services.iaudioService;
         }
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 9ae9824..d6cb9826 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -40,6 +40,7 @@
 import static org.mockito.Matchers.eq;
 import static org.mockito.Matchers.isNull;
 import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.atMost;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
@@ -764,7 +765,7 @@
     }
 
     /**
-     * Test for: @{link DevicePolicyManager#setActivePasswordState}
+     * Test for: @{link DevicePolicyManager#reportPasswordChanged}
      *
      * Validates that when the password for a user changes, the notification broadcast intent
      * {@link DeviceAdminReceiver#ACTION_PASSWORD_CHANGED} is sent to managed profile owners, in
@@ -806,7 +807,7 @@
     }
 
     /**
-     * Test for: @{link DevicePolicyManager#setActivePasswordState}
+     * Test for: @{link DevicePolicyManager#reportPasswordChanged}
      *
      * Validates that when the password for a managed profile changes, the notification broadcast
      * intent {@link DeviceAdminReceiver#ACTION_PASSWORD_CHANGED} is only sent to the profile, not
@@ -4258,6 +4259,10 @@
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         mContext.packageName = admin1.getPackageName();
         setupDeviceOwner();
+        final int userHandle = UserHandle.getUserId(mContext.binder.callingUid);
+        // When there is no lockscreen, user password metrics is always empty.
+        when(getServices().lockSettingsInternal.getUserPasswordMetrics(userHandle))
+                .thenReturn(new PasswordMetrics());
 
         // If no password requirements are set, isActivePasswordSufficient should succeed.
         assertTrue(dpm.isActivePasswordSufficient());
@@ -4266,14 +4271,7 @@
         dpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
 
         reset(mContext.spiedContext);
-        final int userHandle = UserHandle.getUserId(mContext.binder.callingUid);
-        PasswordMetrics passwordMetricsNoSymbols = new PasswordMetrics(
-                DevicePolicyManager.PASSWORD_QUALITY_COMPLEX, 9,
-                8, 2,
-                6, 1,
-                0, 1);
         // This should be ignored, as there is no lock screen.
-        dpm.setActivePasswordState(passwordMetricsNoSymbols, userHandle);
         dpm.reportPasswordChanged(userHandle);
 
         // No broadcast should be sent.
@@ -4290,19 +4288,24 @@
         final int userHandle = UserHandle.getUserId(mContext.binder.callingUid);
         final long ident = mContext.binder.clearCallingIdentity();
 
-        dpm.setActivePasswordState(passwordMetrics, userHandle);
+        when(getServices().lockSettingsInternal.getUserPasswordMetrics(userHandle))
+                .thenReturn(passwordMetrics);
         dpm.reportPasswordChanged(userHandle);
 
         // Drain ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED broadcasts as part of
         // reportPasswordChanged()
-        // This broadcast should be sent 4 times:
+        // This broadcast should be sent 2-4 times:
         // * Twice from calls to DevicePolicyManagerService.updatePasswordExpirationsLocked,
         //   once for each affected user, in DevicePolicyManagerService.reportPasswordChanged.
-        // * Twice from calls to DevicePolicyManagerService.saveSettingsLocked
+        // * Optionally, at most twice from calls to DevicePolicyManagerService.saveSettingsLocked
         //   in DevicePolicyManagerService.reportPasswordChanged, once with the userId
         //   the password change is relevant to and another with the credential owner of said
-        //   userId.
-        verify(mContext.spiedContext, times(4)).sendBroadcastAsUser(
+        //   userId, if the password checkpoint value changes.
+        verify(mContext.spiedContext, atMost(4)).sendBroadcastAsUser(
+                MockUtils.checkIntentAction(
+                        DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
+                MockUtils.checkUserHandle(userHandle));
+        verify(mContext.spiedContext, atLeast(2)).sendBroadcastAsUser(
                 MockUtils.checkIntentAction(
                         DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
                 MockUtils.checkUserHandle(userHandle));
@@ -5224,9 +5227,9 @@
         mServiceContext.permissions.add(permission.REQUEST_PASSWORD_COMPLEXITY);
         when(getServices().userManager.getCredentialOwnerProfile(DpmMockContext.CALLER_USER_HANDLE))
                 .thenReturn(DpmMockContext.CALLER_USER_HANDLE);
-        dpms.mUserPasswordMetrics.put(
-                DpmMockContext.CALLER_USER_HANDLE,
-                PasswordMetrics.computeForPassword("asdf".getBytes()));
+        when(getServices().lockSettingsInternal
+                .getUserPasswordMetrics(DpmMockContext.CALLER_USER_HANDLE))
+                .thenReturn(PasswordMetrics.computeForPassword("asdf".getBytes()));
 
         assertEquals(PASSWORD_COMPLEXITY_MEDIUM, dpm.getPasswordComplexity());
     }
@@ -5241,12 +5244,12 @@
         when(getServices().userManager.getCredentialOwnerProfile(DpmMockContext.CALLER_USER_HANDLE))
                 .thenReturn(parentUser.id);
 
-        dpms.mUserPasswordMetrics.put(
-                DpmMockContext.CALLER_USER_HANDLE,
-                PasswordMetrics.computeForPassword("asdf".getBytes()));
-        dpms.mUserPasswordMetrics.put(
-                parentUser.id,
-                PasswordMetrics.computeForPassword("parentUser".getBytes()));
+        when(getServices().lockSettingsInternal
+                .getUserPasswordMetrics(DpmMockContext.CALLER_USER_HANDLE))
+                .thenReturn(PasswordMetrics.computeForPassword("asdf".getBytes()));
+        when(getServices().lockSettingsInternal
+                .getUserPasswordMetrics(parentUser.id))
+                .thenReturn(PasswordMetrics.computeForPassword("parentUser".getBytes()));
 
         assertEquals(PASSWORD_COMPLEXITY_HIGH, dpm.getPasswordComplexity());
     }
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 f6f365e..b0d0303 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -64,6 +64,7 @@
 
 import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockSettingsInternal;
 import com.android.server.net.NetworkPolicyManagerInternal;
 import com.android.server.wm.ActivityTaskManagerInternal;
 
@@ -102,6 +103,7 @@
     public final IBackupManager ibackupManager;
     public final IAudioService iaudioService;
     public final LockPatternUtils lockPatternUtils;
+    public final LockSettingsInternal lockSettingsInternal;
     public final StorageManagerForMock storageManager;
     public final WifiManager wifiManager;
     public final SettingsForMock settings;
@@ -143,6 +145,7 @@
         ibackupManager = mock(IBackupManager.class);
         iaudioService = mock(IAudioService.class);
         lockPatternUtils = mock(LockPatternUtils.class);
+        lockSettingsInternal = mock(LockSettingsInternal.class);
         storageManager = mock(StorageManagerForMock.class);
         wifiManager = mock(WifiManager.class);
         settings = mock(SettingsForMock.class);
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 1cd590c..341b8f0 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -341,6 +341,7 @@
         final byte[] pattern = "123654".getBytes();
         final byte[] token = "some-high-entropy-secure-token".getBytes();
         initializeCredentialUnderSP(password, PRIMARY_USER_ID);
+        reset(mDevicePolicyManager);
         final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
 
         assertFalse(mService.hasPendingEscrowToken(PRIMARY_USER_ID));
@@ -360,7 +361,8 @@
         flushHandlerTasks();
         final PasswordMetrics metric = PasswordMetrics.computeForCredential(
                 LockPatternUtils.CREDENTIAL_TYPE_PATTERN, pattern);
-        verify(mDevicePolicyManager).setActivePasswordState(metric, PRIMARY_USER_ID);
+        assertEquals(metric, mService.getUserPasswordMetrics(PRIMARY_USER_ID));
+        verify(mDevicePolicyManager).reportPasswordChanged(PRIMARY_USER_ID);
 
         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
                 pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 0, PRIMARY_USER_ID)
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 13748cb..31babd0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -30,6 +30,7 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -866,7 +867,7 @@
         mActivity.setState(PAUSED, "test");
         mActivity.finishIfPossible("test", false /* oomAdj */);
 
-        verify(mActivity).setVisibility(eq(false));
+        verify(mActivity, atLeast(1)).setVisibility(eq(false));
         verify(mActivity.getDisplay().mDisplayContent)
                 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
         verify(mActivity.getDisplay().mDisplayContent).executeAppTransition();
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 60c5f0b..c83e5cb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -26,6 +26,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -1122,6 +1123,22 @@
         assertThat(result).isEqualTo(taskTop);
     }
 
+    @Test
+    public void testNonTopVisibleActivityNotResume() {
+        final ActivityRecord nonTopVisibleActivity =
+                new ActivityBuilder(mService).setTask(mTask).build();
+        new ActivityBuilder(mService).setTask(mTask).build();
+        doReturn(false).when(nonTopVisibleActivity).attachedToProcess();
+        doReturn(true).when(nonTopVisibleActivity).shouldBeVisibleIgnoringKeyguard(anyBoolean());
+        doNothing().when(mSupervisor).startSpecificActivityLocked(any(), anyBoolean(),
+                anyBoolean());
+
+        mStack.ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */,
+                false /* preserveWindows */);
+        verify(mSupervisor).startSpecificActivityLocked(any(), eq(false) /* andResume */,
+                anyBoolean());
+    }
+
     private void verifyShouldSleepActivities(boolean focusedStack,
             boolean keyguardGoingAway, boolean displaySleeping, boolean expected) {
         final ActivityDisplay display = mock(ActivityDisplay.class);
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 e387e18..1f634b1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -36,7 +36,6 @@
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
@@ -160,7 +159,7 @@
 
         // Set initial orientation and update.
         mToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
-        mDisplayContent.updateOrientationFromAppTokens(
+        mDisplayContent.updateOrientation(
                 mDisplayContent.getRequestedOverrideConfiguration(),
                 null /* freezeThisOneIfNeeded */, false /* forceUpdate */);
         assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mDisplayContent.getLastOrientation());
@@ -168,7 +167,7 @@
 
         // Update the orientation to perform 180 degree rotation and check that resize was reported.
         mToken.setOrientation(SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
-        mDisplayContent.updateOrientationFromAppTokens(
+        mDisplayContent.updateOrientation(
                 mDisplayContent.getRequestedOverrideConfiguration(),
                 null /* freezeThisOneIfNeeded */, false /* forceUpdate */);
         // In this test, DC will not get config update. Set the waiting flag to false.
@@ -181,8 +180,8 @@
 
     @Test
     public void testLandscapeSeascapeRotationByPolicy() {
+        // This instance has been spied in {@link TestActivityDisplay}.
         final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
-        spyOn(displayRotation);
 
         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
                 TYPE_BASE_APPLICATION);
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 6289768..44f3ee41 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -445,7 +445,7 @@
                     .computeSafeInsets(200, 400).getDisplayCutout();
 
             dc.mInitialDisplayCutout = cutout;
-            dc.setRotation(Surface.ROTATION_0);
+            dc.getDisplayRotation().setRotation(Surface.ROTATION_0);
             dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo.
 
             assertEquals(cutout, dc.getDisplayInfo().displayCutout);
@@ -476,7 +476,7 @@
                     .computeSafeInsets(displayWidth, displayHeight).getDisplayCutout();
 
             dc.mInitialDisplayCutout = cutout;
-            dc.setRotation(Surface.ROTATION_90);
+            dc.getDisplayRotation().setRotation(Surface.ROTATION_90);
             dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo.
 
             // ----o----------      -------------
@@ -608,18 +608,18 @@
         portraitDisplay.mInitialDisplayHeight = 2000;
         portraitDisplay.mInitialDisplayWidth = 1000;
 
-        portraitDisplay.setRotation(Surface.ROTATION_0);
+        portraitDisplay.getDisplayRotation().setRotation(Surface.ROTATION_0);
         assertFalse(isOptionsPanelAtRight(portraitDisplay.getDisplayId()));
-        portraitDisplay.setRotation(Surface.ROTATION_90);
+        portraitDisplay.getDisplayRotation().setRotation(Surface.ROTATION_90);
         assertTrue(isOptionsPanelAtRight(portraitDisplay.getDisplayId()));
 
         final DisplayContent landscapeDisplay = createNewDisplay();
         landscapeDisplay.mInitialDisplayHeight = 1000;
         landscapeDisplay.mInitialDisplayWidth = 2000;
 
-        landscapeDisplay.setRotation(Surface.ROTATION_0);
+        landscapeDisplay.getDisplayRotation().setRotation(Surface.ROTATION_0);
         assertTrue(isOptionsPanelAtRight(landscapeDisplay.getDisplayId()));
-        landscapeDisplay.setRotation(Surface.ROTATION_90);
+        landscapeDisplay.getDisplayRotation().setRotation(Surface.ROTATION_90);
         assertFalse(isOptionsPanelAtRight(landscapeDisplay.getDisplayId()));
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index 6a3c81ab..3ead9779 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -28,16 +28,12 @@
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
-import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
 import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_RIGHT;
 
@@ -52,7 +48,6 @@
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
-import android.view.Surface;
 import android.view.WindowManager;
 
 import androidx.test.filters.FlakyTest;
@@ -213,32 +208,15 @@
     }
 
     @Test
-    public void testShouldRotateSeamlessly() {
-        final DisplayPolicy policy = mDisplayContent.getDisplayPolicy();
+    public void testComputeTopFullscreenOpaqueWindow() {
         final WindowManager.LayoutParams attrs = mAppWindow.mAttrs;
         attrs.x = attrs.y = 0;
         attrs.height = attrs.width = WindowManager.LayoutParams.MATCH_PARENT;
-        attrs.rotationAnimation = ROTATION_ANIMATION_SEAMLESS;
-        final DisplayRotation displayRotation = mock(DisplayRotation.class);
-        doReturn(Surface.ROTATION_180).when(displayRotation).getUpsideDownRotation();
+        final DisplayPolicy policy = mDisplayContent.getDisplayPolicy();
+        policy.applyPostLayoutPolicyLw(
+                mAppWindow, attrs, null /* attached */, null /* imeTarget */);
 
-        synchronized (mWm.mGlobalLock) {
-            policy.focusChangedLw(null /* lastFocus */, mAppWindow);
-            policy.applyPostLayoutPolicyLw(
-                    mAppWindow, attrs, null /* attached */, null /* imeTarget */);
-            spyOn(policy);
-            doReturn(true).when(policy).navigationBarCanMove();
-            // The focused fullscreen opaque window without override bounds should be able to be
-            // rotated seamlessly.
-            assertTrue(policy.shouldRotateSeamlessly(
-                    displayRotation, Surface.ROTATION_0, Surface.ROTATION_90));
-
-            spyOn(mAppWindow.mAppToken);
-            doReturn(false).when(mAppWindow.mAppToken).matchParentBounds();
-            // No seamless rotation if the window may be positioned with offset after rotation.
-            assertFalse(policy.shouldRotateSeamlessly(
-                    displayRotation, Surface.ROTATION_0, Surface.ROTATION_90));
-        }
+        assertEquals(mAppWindow, policy.getTopFullscreenOpaqueWindow());
     }
 
     @Test
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 49d38c0..059ff3d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -24,6 +24,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.atMost;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
@@ -55,6 +56,7 @@
 import android.platform.test.annotations.Presubmit;
 import android.provider.Settings;
 import android.view.Surface;
+import android.view.WindowManager;
 
 import androidx.test.filters.SmallTest;
 
@@ -584,6 +586,33 @@
                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
     }
 
+    @Test
+    public void testShouldRotateSeamlessly() throws Exception {
+        mBuilder.build();
+
+        final WindowState win = mock(WindowState.class);
+        win.mAppToken = mock(AppWindowToken.class);
+        final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams();
+        attrs.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
+
+        doReturn(attrs).when(win).getAttrs();
+        doReturn(true).when(mMockDisplayPolicy).navigationBarCanMove();
+        doReturn(win).when(mMockDisplayPolicy).getTopFullscreenOpaqueWindow();
+        mMockDisplayContent.mCurrentFocus = win;
+        mTarget.mUpsideDownRotation = Surface.ROTATION_180;
+
+        doReturn(true).when(win.mAppToken).matchParentBounds();
+        // The focused fullscreen opaque window without override bounds should be able to be
+        // rotated seamlessly.
+        assertTrue(mTarget.shouldRotateSeamlessly(
+                Surface.ROTATION_0, Surface.ROTATION_90, false /* forceUpdate */));
+
+        doReturn(false).when(win.mAppToken).matchParentBounds();
+        // No seamless rotation if the window may be positioned with offset after rotation.
+        assertFalse(mTarget.shouldRotateSeamlessly(
+                Surface.ROTATION_0, Surface.ROTATION_90, false /* forceUpdate */));
+    }
+
     // ========================
     // Non-rotation API Tests
     // ========================
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java b/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java
index c143969..778f0ca 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java
@@ -69,20 +69,22 @@
         mSupervisor = supervisor;
         spyOn(this);
         spyOn(mDisplayContent);
+
+        final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
+        spyOn(displayRotation);
         doAnswer(invocation -> {
             // Bypass all the rotation animation and display freezing stuff for testing and just
             // set the rotation we want for the display
-            final DisplayContent dc = mDisplayContent;
-            final int oldRotation = dc.getRotation();
-            final int rotation = dc.getDisplayRotation().rotationForOrientation(
-                    dc.getLastOrientation(), oldRotation);
+            final int oldRotation = displayRotation.getRotation();
+            final int rotation = displayRotation.rotationForOrientation(
+                    displayRotation.getLastOrientation(), oldRotation);
             if (oldRotation == rotation) {
                 return false;
             }
-            dc.setLayoutNeeded();
-            dc.setRotation(rotation);
+            mDisplayContent.setLayoutNeeded();
+            displayRotation.setRotation(rotation);
             return true;
-        }).when(mDisplayContent).updateRotationUnchecked(anyBoolean());
+        }).when(displayRotation).updateRotationUnchecked(anyBoolean());
     }
 
     @SuppressWarnings("TypeParameterUnusedInFormals")
diff --git a/telecomm/java/android/telecom/AudioState.java b/telecomm/java/android/telecom/AudioState.java
index 6b9b83d..8b8c86b 100644
--- a/telecomm/java/android/telecom/AudioState.java
+++ b/telecomm/java/android/telecom/AudioState.java
@@ -16,6 +16,8 @@
 
 package android.telecom;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Build;
@@ -81,7 +83,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (obj == null) {
             return false;
         }
@@ -93,6 +95,7 @@
                 getSupportedRouteMask() == state.getSupportedRouteMask();
     }
 
+    @NonNull
     @Override
     public String toString() {
         return String.format(Locale.US,
diff --git a/telephony/java/android/telephony/CallAttributes.java b/telephony/java/android/telephony/CallAttributes.java
index 3a34005..1c03d80 100644
--- a/telephony/java/android/telephony/CallAttributes.java
+++ b/telephony/java/android/telephony/CallAttributes.java
@@ -17,6 +17,7 @@
 package android.telephony;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -44,6 +45,7 @@
         this.mCallQuality = callQuality;
     }
 
+    @NonNull
     @Override
     public String toString() {
         return "mPreciseCallState=" + mPreciseCallState + " mNetworkType=" + mNetworkType
@@ -109,7 +111,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (o == null || !(o instanceof CallAttributes) || hashCode() != o.hashCode()) {
             return false;
         }
diff --git a/telephony/java/android/telephony/CallQuality.java b/telephony/java/android/telephony/CallQuality.java
index 10a04a9..028280c 100644
--- a/telephony/java/android/telephony/CallQuality.java
+++ b/telephony/java/android/telephony/CallQuality.java
@@ -17,6 +17,8 @@
 package android.telephony;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -252,6 +254,7 @@
     }
 
     // Parcelable things
+    @NonNull
     @Override
     public String toString() {
         return "CallQuality: {downlinkCallQualityLevel=" + mDownlinkCallQualityLevel
@@ -285,7 +288,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (o == null || !(o instanceof CallQuality) || hashCode() != o.hashCode()) {
             return false;
         }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 654b54d..2aca206 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2791,6 +2791,13 @@
             "opportunistic_network_data_switch_exit_hysteresis_time_long";
 
     /**
+     * Controls time in milli seconds until DcTracker reevaluates 5G connection state.
+     * @hide
+     */
+    public static final String KEY_5G_WATCHDOG_TIME_MS_LONG =
+            "5g_watchdog_time_long";
+
+    /**
      * Indicates zero or more emergency number prefix(es), because some carrier requires
      * if users dial an emergency number address with a specific prefix, the combination of the
      * prefix and the address is also a valid emergency number to dial. For example, an emergency
@@ -3565,6 +3572,8 @@
         sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_HYSTERESIS_TIME_LONG, 10000);
         /* Default value is 3 seconds. */
         sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG, 3000);
+        /* Default value is 1 hour. */
+        sDefaults.putLong(KEY_5G_WATCHDOG_TIME_MS_LONG, 3600000);
         sDefaults.putAll(Gps.getDefaults());
         sDefaults.putAll(Wifi.getDefaults());
         sDefaults.putIntArray(KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY,
@@ -3799,7 +3808,7 @@
      * @see #getConfigForSubId
      */
     @Nullable
-    public PersistableBundle getConfigByComponentForSubId(String prefix, int subId) {
+    public PersistableBundle getConfigByComponentForSubId(@NonNull String prefix, int subId) {
         PersistableBundle configs = getConfigForSubId(subId);
 
         if (configs == null) {
diff --git a/telephony/java/android/telephony/CarrierRestrictionRules.java b/telephony/java/android/telephony/CarrierRestrictionRules.java
index 950ae6c..c138018 100644
--- a/telephony/java/android/telephony/CarrierRestrictionRules.java
+++ b/telephony/java/android/telephony/CarrierRestrictionRules.java
@@ -323,6 +323,7 @@
         }
     };
 
+    @NonNull
     @Override
     public String toString() {
         return "CarrierRestrictionRules(allowed:" + mAllowedCarriers + ", excluded:"
diff --git a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
index 3dd9318..407ced7 100644
--- a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
+++ b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
@@ -17,6 +17,7 @@
 package android.telephony;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.os.Parcel;
@@ -134,6 +135,7 @@
         return 0;
     }
 
+    @NonNull
     @Override
     public String toString() {
         return new StringBuilder().append(this.getClass().getName())
@@ -155,7 +157,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (this == o) return true;
 
         if (!(o instanceof DataSpecificRegistrationInfo)) return false;
diff --git a/telephony/java/android/telephony/LteVopsSupportInfo.java b/telephony/java/android/telephony/LteVopsSupportInfo.java
index ec9f078..7994c1b 100644
--- a/telephony/java/android/telephony/LteVopsSupportInfo.java
+++ b/telephony/java/android/telephony/LteVopsSupportInfo.java
@@ -17,6 +17,8 @@
 package android.telephony;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.os.Parcel;
@@ -94,7 +96,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (o == null || !(o instanceof LteVopsSupportInfo)) {
             return false;
         }
@@ -112,6 +114,7 @@
     /**
      * @return string representation.
      */
+    @NonNull
     @Override
     public String toString() {
         return ("LteVopsSupportInfo : "
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index 2fae949..a76b8da 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -501,6 +501,7 @@
         }
     }
 
+    @NonNull
     @Override
     public String toString() {
         return new StringBuilder("NetworkRegistrationInfo{")
@@ -531,7 +532,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (this == o) return true;
 
         if (!(o instanceof NetworkRegistrationInfo)) {
diff --git a/telephony/java/android/telephony/PhoneNumberRange.java b/telephony/java/android/telephony/PhoneNumberRange.java
index c35a485..e6f107e 100644
--- a/telephony/java/android/telephony/PhoneNumberRange.java
+++ b/telephony/java/android/telephony/PhoneNumberRange.java
@@ -17,6 +17,7 @@
 package android.telephony;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -104,7 +105,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
         PhoneNumberRange that = (PhoneNumberRange) o;
@@ -119,6 +120,7 @@
         return Objects.hash(mCountryCode, mPrefix, mLowerBound, mUpperBound);
     }
 
+    @NonNull
     @Override
     public String toString() {
         return "PhoneNumberRange{"
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index f03a9dc..af3ba5e 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -217,6 +217,9 @@
         }
 
         String scheme = uri.getScheme();
+        if (scheme == null) {
+            return null;
+        }
 
         if (scheme.equals("tel") || scheme.equals("sip")) {
             return uri.getSchemeSpecificPart();
diff --git a/telephony/java/android/telephony/PreciseCallState.java b/telephony/java/android/telephony/PreciseCallState.java
index 5fb9bac..701a375 100644
--- a/telephony/java/android/telephony/PreciseCallState.java
+++ b/telephony/java/android/telephony/PreciseCallState.java
@@ -17,6 +17,8 @@
 package android.telephony;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
@@ -276,7 +278,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (this == obj) {
             return true;
         }
@@ -294,6 +296,7 @@
                 && mPreciseDisconnectCause == other.mPreciseDisconnectCause);
     }
 
+    @NonNull
     @Override
     public String toString() {
         StringBuffer sb = new StringBuffer();
diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java
index cd4fbac..90d443a 100644
--- a/telephony/java/android/telephony/PreciseDataConnectionState.java
+++ b/telephony/java/android/telephony/PreciseDataConnectionState.java
@@ -177,7 +177,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
 
         if (!(obj instanceof PreciseDataConnectionState)) {
             return false;
@@ -191,6 +191,7 @@
                 && mState == other.mState;
     }
 
+    @NonNull
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index b44e4f1..cd0f57e 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -53,7 +53,6 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Executor;
@@ -1555,15 +1554,13 @@
     public boolean
     deleteMessageFromIcc(int messageIndex) {
         boolean success = false;
-        byte[] pdu = new byte[SMS_RECORD_LENGTH-1];
-        Arrays.fill(pdu, (byte)0xff);
 
         try {
             ISms iSms = getISmsService();
             if (iSms != null) {
                 success = iSms.updateMessageOnIccEfForSubscriber(getSubscriptionId(),
                         ActivityThread.currentPackageName(),
-                        messageIndex, STATUS_ON_ICC_FREE, pdu);
+                        messageIndex, STATUS_ON_ICC_FREE, null /* pdu */);
             }
         } catch (RemoteException ex) {
             // ignore it
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 5e47e49..d93d1d6a 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -53,6 +53,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.telephony.TelephonyManager.NetworkType;
 import android.telephony.euicc.EuiccManager;
 import android.telephony.ims.ImsMmTelManager;
 import android.util.DisplayMetrics;
@@ -2454,10 +2455,51 @@
      */
     public void setSubscriptionOverrideUnmetered(int subId, boolean overrideUnmetered,
             @DurationMillisLong long timeoutMillis) {
+        setSubscriptionOverrideUnmetered(subId, null, overrideUnmetered, timeoutMillis);
+    }
+
+    /**
+     * Temporarily override the billing relationship between a carrier and
+     * a specific subscriber to be considered unmetered for the given network
+     * types. This will be reflected to apps via
+     * {@link NetworkCapabilities#NET_CAPABILITY_NOT_METERED}.
+     * This method is only accessible to the following narrow set of apps:
+     * <ul>
+     * <li>The carrier app for this subscriberId, as determined by
+     * {@link TelephonyManager#hasCarrierPrivileges()}.
+     * <li>The carrier app explicitly delegated access through
+     * {@link CarrierConfigManager#KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING}.
+     * </ul>
+     *
+     * @param subId the subscriber this override applies to.
+     * @param networkTypes all network types to set an override for. A null
+     *            network type means to apply the override to all network types.
+     *            Any unspecified network types will default to metered.
+     * @param overrideUnmetered set if the billing relationship should be
+     *            considered unmetered.
+     * @param timeoutMillis the timeout after which the requested override will
+     *            be automatically cleared, or {@code 0} to leave in the
+     *            requested state until explicitly cleared, or the next reboot,
+     *            whichever happens first.
+     * @throws SecurityException if the caller doesn't meet the requirements
+     *            outlined above.
+     * {@hide}
+     */
+    public void setSubscriptionOverrideUnmetered(int subId,
+            @Nullable @NetworkType int[] networkTypes, boolean overrideUnmetered,
+            @DurationMillisLong long timeoutMillis) {
         try {
+            long networkTypeMask = 0;
+            if (networkTypes != null) {
+                for (int networkType : networkTypes) {
+                    networkTypeMask |= TelephonyManager.getBitMaskForNetworkType(networkType);
+                }
+            } else {
+                networkTypeMask = ~0;
+            }
             final int overrideValue = overrideUnmetered ? OVERRIDE_UNMETERED : 0;
             getNetworkPolicy().setSubscriptionOverride(subId, OVERRIDE_UNMETERED, overrideValue,
-                    timeoutMillis, mContext.getOpPackageName());
+                    networkTypeMask, timeoutMillis, mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2489,10 +2531,52 @@
      */
     public void setSubscriptionOverrideCongested(int subId, boolean overrideCongested,
             @DurationMillisLong long timeoutMillis) {
+        setSubscriptionOverrideCongested(subId, null, overrideCongested, timeoutMillis);
+    }
+
+    /**
+     * Temporarily override the billing relationship plan between a carrier and
+     * a specific subscriber to be considered congested. This will cause the
+     * device to delay certain network requests when possible, such as developer
+     * jobs that are willing to run in a flexible time window.
+     * <p>
+     * This method is only accessible to the following narrow set of apps:
+     * <ul>
+     * <li>The carrier app for this subscriberId, as determined by
+     * {@link TelephonyManager#hasCarrierPrivileges()}.
+     * <li>The carrier app explicitly delegated access through
+     * {@link CarrierConfigManager#KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING}.
+     * </ul>
+     *
+     * @param subId the subscriber this override applies to.
+     * @param networkTypes all network types to set an override for. A null
+     *            network type means to apply the override to all network types.
+     *            Any unspecified network types will default to not congested.
+     * @param overrideCongested set if the subscription should be considered
+     *            congested.
+     * @param timeoutMillis the timeout after which the requested override will
+     *            be automatically cleared, or {@code 0} to leave in the
+     *            requested state until explicitly cleared, or the next reboot,
+     *            whichever happens first.
+     * @throws SecurityException if the caller doesn't meet the requirements
+     *             outlined above.
+     * @hide
+     */
+    public void setSubscriptionOverrideCongested(int subId,
+            @Nullable @NetworkType int[] networkTypes, boolean overrideCongested,
+            @DurationMillisLong long timeoutMillis) {
         try {
+            long networkTypeMask = 0;
+            if (networkTypes != null) {
+                for (int networkType : networkTypes) {
+                    networkTypeMask |= TelephonyManager.getBitMaskForNetworkType(networkType);
+                }
+            } else {
+                networkTypeMask = ~0;
+            }
             final int overrideValue = overrideCongested ? OVERRIDE_CONGESTED : 0;
             getNetworkPolicy().setSubscriptionOverride(subId, OVERRIDE_CONGESTED, overrideValue,
-                    timeoutMillis, mContext.getOpPackageName());
+                    networkTypeMask, timeoutMillis, mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/telephony/java/android/telephony/SubscriptionPlan.java b/telephony/java/android/telephony/SubscriptionPlan.java
index e0838b3..ec2050f 100644
--- a/telephony/java/android/telephony/SubscriptionPlan.java
+++ b/telephony/java/android/telephony/SubscriptionPlan.java
@@ -131,7 +131,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (obj instanceof SubscriptionPlan) {
             final SubscriptionPlan other = (SubscriptionPlan) obj;
             return Objects.equals(cycleRule, other.cycleRule)
diff --git a/telephony/java/android/telephony/TelephonyHistogram.java b/telephony/java/android/telephony/TelephonyHistogram.java
index 63bdac5..b94cb60 100644
--- a/telephony/java/android/telephony/TelephonyHistogram.java
+++ b/telephony/java/android/telephony/TelephonyHistogram.java
@@ -15,13 +15,12 @@
  */
 package android.telephony;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.List;
 
 /**
  * Parcelable class to store Telephony histogram.
@@ -238,6 +237,8 @@
         }
     }
 
+    @NonNull
+    @Override
     public String toString() {
         String basic = " Histogram id = " + mId + " Time(ms): min = " + mMinTimeMs + " max = "
                 + mMaxTimeMs + " avg = " + mAverageTimeMs + " Count = " + mSampleCount;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 553bff2..475563d 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2829,6 +2829,55 @@
         }
     }
 
+    /**
+     * Returns the bitmask for a given technology (network type)
+     * @param networkType for which bitmask is returned
+     * @return the network type bitmask
+     * {@hide}
+     */
+    public static @NetworkTypeBitMask long getBitMaskForNetworkType(@NetworkType int networkType) {
+        switch(networkType) {
+            case NETWORK_TYPE_GSM:
+                return NETWORK_TYPE_BITMASK_GSM;
+            case NETWORK_TYPE_GPRS:
+                return NETWORK_TYPE_BITMASK_GPRS;
+            case NETWORK_TYPE_EDGE:
+                return NETWORK_TYPE_BITMASK_EDGE;
+            case NETWORK_TYPE_CDMA:
+                return NETWORK_TYPE_BITMASK_CDMA;
+            case NETWORK_TYPE_1xRTT:
+                return NETWORK_TYPE_BITMASK_1xRTT;
+            case NETWORK_TYPE_EVDO_0:
+                return NETWORK_TYPE_BITMASK_EVDO_0;
+            case NETWORK_TYPE_EVDO_A:
+                return NETWORK_TYPE_BITMASK_EVDO_A;
+            case NETWORK_TYPE_EVDO_B:
+                return NETWORK_TYPE_BITMASK_EVDO_B;
+            case NETWORK_TYPE_EHRPD:
+                return NETWORK_TYPE_BITMASK_EHRPD;
+            case NETWORK_TYPE_HSUPA:
+                return NETWORK_TYPE_BITMASK_HSUPA;
+            case NETWORK_TYPE_HSDPA:
+                return NETWORK_TYPE_BITMASK_HSDPA;
+            case NETWORK_TYPE_HSPA:
+                return NETWORK_TYPE_BITMASK_HSPA;
+            case NETWORK_TYPE_HSPAP:
+                return NETWORK_TYPE_BITMASK_HSPAP;
+            case NETWORK_TYPE_UMTS:
+                return NETWORK_TYPE_BITMASK_UMTS;
+            case NETWORK_TYPE_TD_SCDMA:
+                return NETWORK_TYPE_BITMASK_TD_SCDMA;
+            case NETWORK_TYPE_LTE:
+                return NETWORK_TYPE_BITMASK_LTE;
+            case NETWORK_TYPE_LTE_CA:
+                return NETWORK_TYPE_BITMASK_LTE_CA;
+            case NETWORK_TYPE_NR:
+                return NETWORK_TYPE_BITMASK_NR;
+            default:
+                return NETWORK_TYPE_BITMASK_UNKNOWN;
+        }
+    }
+
     //
     //
     // SIM Card
diff --git a/telephony/java/android/telephony/UiccAccessRule.java b/telephony/java/android/telephony/UiccAccessRule.java
index 37a4491..811722f 100644
--- a/telephony/java/android/telephony/UiccAccessRule.java
+++ b/telephony/java/android/telephony/UiccAccessRule.java
@@ -15,6 +15,7 @@
  */
 package android.telephony;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.content.pm.PackageInfo;
@@ -213,7 +214,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (this == obj) {
             return true;
         }
@@ -236,6 +237,7 @@
         return result;
     }
 
+    @NonNull
     @Override
     public String toString() {
         return "cert: " + IccUtils.bytesToHexString(mCertificateHash) + " pkg: " +
diff --git a/telephony/java/android/telephony/UiccSlotInfo.java b/telephony/java/android/telephony/UiccSlotInfo.java
index fb1da7b..a0e949a 100644
--- a/telephony/java/android/telephony/UiccSlotInfo.java
+++ b/telephony/java/android/telephony/UiccSlotInfo.java
@@ -16,6 +16,8 @@
 package android.telephony;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -179,7 +181,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (this == obj) {
             return true;
         }
@@ -210,6 +212,7 @@
         return result;
     }
 
+    @NonNull
     @Override
     public String toString() {
         return "UiccSlotInfo (mIsActive="
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
index 17699d7..9170e88 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -213,6 +213,7 @@
      */
     public int getMtu() { return mMtu; }
 
+    @NonNull
     @Override
     public String toString() {
         StringBuffer sb = new StringBuffer();
@@ -233,7 +234,7 @@
     }
 
     @Override
-    public boolean equals (Object o) {
+    public boolean equals(@Nullable Object o) {
         if (this == o) return true;
 
         if (!(o instanceof DataCallResponse)) {
diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java
index c53ade1..0d79ec9 100644
--- a/telephony/java/android/telephony/data/DataProfile.java
+++ b/telephony/java/android/telephony/data/DataProfile.java
@@ -257,6 +257,7 @@
         return 0;
     }
 
+    @NonNull
     @Override
     public String toString() {
         return "DataProfile=" + mProfileId + "/" + mProtocolType + "/" + mAuthType
@@ -303,7 +304,7 @@
     };
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
         DataProfile that = (DataProfile) o;
diff --git a/telephony/java/android/telephony/euicc/EuiccNotification.java b/telephony/java/android/telephony/euicc/EuiccNotification.java
index b27f775..c348cff 100644
--- a/telephony/java/android/telephony/euicc/EuiccNotification.java
+++ b/telephony/java/android/telephony/euicc/EuiccNotification.java
@@ -16,6 +16,7 @@
 package android.telephony.euicc;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
@@ -107,7 +108,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (this == obj) {
             return true;
         }
@@ -132,6 +133,7 @@
         return result;
     }
 
+    @NonNull
     @Override
     public String toString() {
         return "EuiccNotification (seq="
diff --git a/telephony/java/android/telephony/euicc/EuiccRulesAuthTable.java b/telephony/java/android/telephony/euicc/EuiccRulesAuthTable.java
index 89842ae..d5a05ae 100644
--- a/telephony/java/android/telephony/euicc/EuiccRulesAuthTable.java
+++ b/telephony/java/android/telephony/euicc/EuiccRulesAuthTable.java
@@ -16,6 +16,7 @@
 package android.telephony.euicc;
 
 import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -28,7 +29,6 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
-import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -204,7 +204,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (this == obj) {
             return true;
         }
diff --git a/telephony/java/android/telephony/ims/ImsCallForwardInfo.java b/telephony/java/android/telephony/ims/ImsCallForwardInfo.java
index 9b72d58..79cdfef 100644
--- a/telephony/java/android/telephony/ims/ImsCallForwardInfo.java
+++ b/telephony/java/android/telephony/ims/ImsCallForwardInfo.java
@@ -185,6 +185,7 @@
         out.writeInt(mServiceClass);
     }
 
+    @NonNull
     @Override
     public String toString() {
         return super.toString() + ", Condition: " + mCondition
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index 2087914..77ee205 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -539,7 +539,7 @@
         mMediaProfile = profile.mMediaProfile;
     }
 
-
+    @NonNull
     @Override
     public String toString() {
         return "{ serviceType=" + mServiceType
diff --git a/telephony/java/android/telephony/ims/ImsConferenceState.java b/telephony/java/android/telephony/ims/ImsConferenceState.java
index 44595b5..6f062f4 100644
--- a/telephony/java/android/telephony/ims/ImsConferenceState.java
+++ b/telephony/java/android/telephony/ims/ImsConferenceState.java
@@ -16,6 +16,7 @@
 
 package android.telephony.ims;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -176,6 +177,7 @@
         return Call.STATE_ACTIVE;
     }
 
+    @NonNull
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
diff --git a/telephony/java/android/telephony/ims/ImsExternalCallState.java b/telephony/java/android/telephony/ims/ImsExternalCallState.java
index 37b11ed..eb2ebca 100644
--- a/telephony/java/android/telephony/ims/ImsExternalCallState.java
+++ b/telephony/java/android/telephony/ims/ImsExternalCallState.java
@@ -213,6 +213,7 @@
         return mIsHeld;
     }
 
+    @NonNull
     @Override
     public String toString() {
         return "ImsExternalCallState { mCallId = " + mCallId +
diff --git a/telephony/java/android/telephony/ims/ImsReasonInfo.java b/telephony/java/android/telephony/ims/ImsReasonInfo.java
index 20aba4d..1e0d9a78 100644
--- a/telephony/java/android/telephony/ims/ImsReasonInfo.java
+++ b/telephony/java/android/telephony/ims/ImsReasonInfo.java
@@ -17,6 +17,7 @@
 package android.telephony.ims;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
@@ -1183,6 +1184,8 @@
     /**
      * @return the string format of {@link ImsReasonInfo}
      */
+    @NonNull
+    @Override
     public String toString() {
         return "ImsReasonInfo :: {" + mCode + ", " + mExtraCode + ", " + mExtraMessage + "}";
     }
diff --git a/telephony/java/android/telephony/ims/ImsSsData.java b/telephony/java/android/telephony/ims/ImsSsData.java
index 32b4382..ec2ff6c 100644
--- a/telephony/java/android/telephony/ims/ImsSsData.java
+++ b/telephony/java/android/telephony/ims/ImsSsData.java
@@ -570,6 +570,8 @@
         return mCfInfo;
     }
 
+    @NonNull
+    @Override
     public String toString() {
         return "[ImsSsData] " + "ServiceType: " + getServiceType()
             + " RequestType: " + getRequestType()
diff --git a/telephony/java/android/telephony/ims/ImsSsInfo.java b/telephony/java/android/telephony/ims/ImsSsInfo.java
index 9912ece..be34f9d 100644
--- a/telephony/java/android/telephony/ims/ImsSsInfo.java
+++ b/telephony/java/android/telephony/ims/ImsSsInfo.java
@@ -254,6 +254,7 @@
         out.writeInt(mClirOutgoingState);
     }
 
+    @NonNull
     @Override
     public String toString() {
         return super.toString() + ", Status: " + ((mStatus == 0) ? "disabled" : "enabled")
diff --git a/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java b/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
index fd75a6b..c1f059e 100644
--- a/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
+++ b/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
@@ -16,6 +16,7 @@
 
 package android.telephony.ims;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
@@ -194,6 +195,7 @@
         mRttMode = profile.mRttMode;
     }
 
+    @NonNull
     @Override
     public String toString() {
         return "{ audioQuality=" + mAudioQuality +
diff --git a/telephony/java/android/telephony/ims/ImsSuppServiceNotification.java b/telephony/java/android/telephony/ims/ImsSuppServiceNotification.java
index 2e4288d..1630368 100644
--- a/telephony/java/android/telephony/ims/ImsSuppServiceNotification.java
+++ b/telephony/java/android/telephony/ims/ImsSuppServiceNotification.java
@@ -17,6 +17,7 @@
 
 package android.telephony.ims;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -67,6 +68,7 @@
         history = in.createStringArray();
     }
 
+    @NonNull
     @Override
     public String toString() {
         return "{ notificationType=" + notificationType +
diff --git a/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java b/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java
index 80fc09e..87a5094 100644
--- a/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java
+++ b/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java
@@ -16,6 +16,7 @@
 
 package android.telephony.ims.feature;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -98,6 +99,7 @@
             return radioTech;
         }
 
+        @NonNull
         @Override
         public String toString() {
             return "CapabilityPair{"
@@ -219,6 +221,7 @@
         }
     }
 
+    @NonNull
     @Override
     public String toString() {
         return "CapabilityChangeRequest{"
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index 056a0ab..20c191d 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -291,6 +291,7 @@
             return super.isCapable(capabilities);
         }
 
+        @NonNull
         @Override
         public String toString() {
             StringBuilder builder = new StringBuilder("MmTel Capabilities - [");
diff --git a/telephony/java/android/telephony/ims/stub/ImsFeatureConfiguration.java b/telephony/java/android/telephony/ims/stub/ImsFeatureConfiguration.java
index 3b298bb..cd9ebbf 100644
--- a/telephony/java/android/telephony/ims/stub/ImsFeatureConfiguration.java
+++ b/telephony/java/android/telephony/ims/stub/ImsFeatureConfiguration.java
@@ -16,6 +16,8 @@
 
 package android.telephony.ims.stub;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -60,7 +62,7 @@
         }
 
         @Override
-        public boolean equals(Object o) {
+        public boolean equals(@Nullable Object o) {
             if (this == o) return true;
             if (o == null || getClass() != o.getClass()) return false;
 
@@ -77,6 +79,7 @@
             return result;
         }
 
+        @NonNull
         @Override
         public String toString() {
             return "{s=" + slotId + ", f=" + ImsFeature.FEATURE_LOG_MAP.get(featureType) + "}";
diff --git a/telephony/java/android/telephony/mbms/DownloadRequest.java b/telephony/java/android/telephony/mbms/DownloadRequest.java
index 52b51d2..ac258cd 100644
--- a/telephony/java/android/telephony/mbms/DownloadRequest.java
+++ b/telephony/java/android/telephony/mbms/DownloadRequest.java
@@ -17,6 +17,7 @@
 package android.telephony.mbms;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.content.Intent;
@@ -381,7 +382,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (this == o) return true;
         if (o == null) {
             return false;
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index e1113eb..668a6af 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -111,6 +111,9 @@
     public static final int EVENT_DATA_SERVICE_BINDING_CHANGED = BASE + 49;
     public static final int EVENT_DEVICE_PROVISIONED_CHANGE = BASE + 50;
     public static final int EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED = BASE + 51;
+    public static final int EVENT_5G_NETWORK_CHANGED = BASE + 52;
+    public static final int EVENT_5G_TIMER_HYSTERESIS = BASE + 53;
+    public static final int EVENT_5G_TIMER_WATCHDOG = BASE + 54;
 
     /***** Constants *****/
 
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index 6b3126d..d892e55 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -696,6 +696,89 @@
     }
 
     /**
+     * Pre-processes an SMS WAP for Teleservice Id 0xFDEA(65002).
+     *
+     * It requires an additional header parsing to extract new Message Identifier and new User Data
+     * from WDP SMS User Data.
+     *
+     * - WDP SMS User Data Subparameter =
+     *   |User Data SUBPARAMETER_ID ~ NUM_FIELDS| + |CHARi| + |RESERVED|
+     *
+     * - WDP SMS User Data Subparameter CHARi =
+     *   |New Message Identifier Subparameter(HEADER_IND = 0)| +
+     *   |New User Data Subparameter(MSG_ENCODING = ENCODING_OCTET)|
+     *
+     * @return true if preprocessing is successful, false otherwise.
+     */
+    public boolean preprocessCdmaFdeaWap() {
+        try {
+            BitwiseInputStream inStream = new BitwiseInputStream(mUserData);
+
+            // Message Identifier SUBPARAMETER_ID(0x00)
+            if (inStream.read(8) != 0x00) {
+                Rlog.e(LOG_TAG, "Invalid FDEA WDP Header Message Identifier SUBPARAMETER_ID");
+                return false;
+            }
+
+            // Message Identifier SUBPARAM_LEN(0x03)
+            if (inStream.read(8) != 0x03) {
+                Rlog.e(LOG_TAG, "Invalid FDEA WDP Header Message Identifier SUBPARAM_LEN");
+                return false;
+            }
+
+            // Message Identifier MESSAGE_TYPE
+            mBearerData.messageType = inStream.read(4);
+
+            // Message Identifier MESSAGE_ID
+            int msgId = inStream.read(8) << 8;
+            msgId |= inStream.read(8);
+            mBearerData.messageId = msgId;
+            mMessageRef = msgId;
+
+            // Message Identifier HEADER_IND
+            mBearerData.hasUserDataHeader = (inStream.read(1) == 1);
+            if (mBearerData.hasUserDataHeader) {
+                Rlog.e(LOG_TAG, "Invalid FDEA WDP Header Message Identifier HEADER_IND");
+                return false;
+            }
+
+            // Message Identifier RESERVED
+            inStream.skip(3);
+
+            // User Data SUBPARAMETER_ID(0x01)
+            if (inStream.read(8) != 0x01) {
+                Rlog.e(LOG_TAG, "Invalid FDEA WDP Header User Data SUBPARAMETER_ID");
+                return false;
+            }
+
+            // User Data SUBPARAM_LEN
+            int userDataLen = inStream.read(8) * 8;
+
+            // User Data MSG_ENCODING
+            mBearerData.userData.msgEncoding = inStream.read(5);
+            int consumedBits = 5;
+            if (mBearerData.userData.msgEncoding != UserData.ENCODING_OCTET) {
+                Rlog.e(LOG_TAG, "Invalid FDEA WDP Header User Data MSG_ENCODING");
+                return false;
+            }
+
+            // User Data NUM_FIELDS
+            mBearerData.userData.numFields = inStream.read(8);
+            consumedBits += 8;
+
+            int remainingBits = userDataLen - consumedBits;
+            int dataBits = mBearerData.userData.numFields * 8;
+            dataBits = dataBits < remainingBits ? dataBits : remainingBits;
+            mBearerData.userData.payload = inStream.readByteArray(dataBits);
+            mUserData = mBearerData.userData.payload;
+            return true;
+        } catch (BitwiseInputStream.AccessException ex) {
+            Rlog.e(LOG_TAG, "Fail to preprocess FDEA WAP: " + ex);
+        }
+        return false;
+    }
+
+    /**
      * Parses a SMS message from its BearerData stream.
      */
     @UnsupportedAppUsage
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
index 2181bc4..d9be548 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -781,13 +781,13 @@
                                       " > " + SmsConstants.MAX_USER_DATA_BYTES + " bytes)");
         }
 
-        /*
-         * TODO(cleanup): figure out what the right answer is WRT paddingBits field
-         *
-         *   userData.paddingBits = (userData.payload.length * 8) - (userData.numFields * 7);
-         *   userData.paddingBits = 0; // XXX this seems better, but why?
-         *
-         */
+        if (bData.userData.msgEncoding == UserData.ENCODING_7BIT_ASCII) {
+            bData.userData.paddingBits =
+                    (bData.userData.payload.length * 8) - (bData.userData.numFields * 7);
+        } else {
+            bData.userData.paddingBits = 0;
+        }
+
         int dataBits = (bData.userData.payload.length * 8) - bData.userData.paddingBits;
         int paramBits = dataBits + 13;
         if ((bData.userData.msgEncoding == UserData.ENCODING_IS91_EXTENDED_PROTOCOL) ||
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
index 6af174c..3440c65 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
@@ -39,6 +39,9 @@
     static public final int TELESERVICE_WEMT              = 0x1005;
     static public final int TELESERVICE_SCPT              = 0x1006;
 
+    /** Carriers specific Teleservice IDs. */
+    public static final int TELESERVICE_FDEA_WAP = 0xFDEA; // 65002
+
     /**
      * The following are defined as extensions to the standard teleservices
      */
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index 5bb818b..da32c8c 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -1247,6 +1247,7 @@
 
         int encodingType = ENCODING_UNKNOWN;
 
+        Resources r = Resources.getSystem();
         // Look up the data encoding scheme
         if ((mDataCodingScheme & 0x80) == 0) {
             userDataCompressed = (0 != (mDataCodingScheme & 0x20));
@@ -1268,7 +1269,6 @@
                 case 1: // 8 bit data
                     //Support decoding the user data payload as pack GSM 8-bit (a GSM alphabet string
                     //that's stored in 8-bit unpacked format) characters.
-                    Resources r = Resources.getSystem();
                     if (r.getBoolean(com.android.internal.
                             R.bool.config_sms_decode_gsm_8bit_data)) {
                         encodingType = ENCODING_8BIT;
@@ -1278,7 +1278,8 @@
                 case 3: // reserved
                     Rlog.w(LOG_TAG, "1 - Unsupported SMS data coding scheme "
                             + (mDataCodingScheme & 0xff));
-                    encodingType = ENCODING_8BIT;
+                    encodingType = r.getInteger(
+                            com.android.internal.R.integer.default_reserved_data_coding_scheme);
                     break;
                 }
             }
@@ -1432,7 +1433,6 @@
         case ENCODING_8BIT:
             //Support decoding the user data payload as pack GSM 8-bit (a GSM alphabet string
             //that's stored in 8-bit unpacked format) characters.
-            Resources r = Resources.getSystem();
             if (r.getBoolean(com.android.internal.
                     R.bool.config_sms_decode_gsm_8bit_data)) {
                 mMessageBody = p.getUserDataGSM8bit(count);
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index 9a653cf..34ac3dc 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -19,14 +19,14 @@
 java_sdk_library {
     name: "android.test.mock",
 
-    srcs: ["src/**/*.java"],
+    srcs: [
+        "src/**/*.java",
+        ":framework-srcs",
+    ],
 
     api_packages: [
         "android.test.mock",
     ],
-
-    srcs_lib: "framework-minus-apex",
-    srcs_lib_whitelist_pkgs: ["android"],
     compile_dex: true,
 }
 
diff --git a/tests/BackgroundDexOptServiceIntegrationTests/AndroidManifest.xml b/tests/BackgroundDexOptServiceIntegrationTests/AndroidManifest.xml
index aec9f77..7291dc7 100644
--- a/tests/BackgroundDexOptServiceIntegrationTests/AndroidManifest.xml
+++ b/tests/BackgroundDexOptServiceIntegrationTests/AndroidManifest.xml
@@ -28,6 +28,8 @@
     <uses-permission android:name="android.permission.SET_TIME" />
     <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" />
+    <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java b/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java
index 7d826f7..4cd56c3 100644
--- a/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java
+++ b/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java
@@ -22,6 +22,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.SystemProperties;
 import android.os.storage.StorageManager;
+import android.provider.DeviceConfig;
 import android.util.Log;
 
 import androidx.test.InstrumentationRegistry;
@@ -30,7 +31,9 @@
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.BeforeClass;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
@@ -52,6 +55,13 @@
  * 3. Under low storage conditions and package is recently used, check
  * that dexopt upgrades test app to $(getprop pm.dexopt.bg-dexopt).
  *
+ * When downgrade feature is on (downgrade_unused_apps_enabled flag is set to true):
+ * 4  On low storage, check that the inactive packages are downgraded.
+ * 5. On low storage, check that used packages are upgraded.
+ * 6. On storage completely full, dexopt fails.
+ * 7. Not on low storage, unused packages are upgraded.
+ * 8. Low storage, unused app is downgraded. When app is used again, app is upgraded.
+ *
  * Each test case runs "cmd package bg-dexopt-job com.android.frameworks.bgdexopttest".
  *
  * The setup for these tests make sure this package has been configured to have been recently used
@@ -59,6 +69,10 @@
  * recently used, it sets the time forward more than
  * `getprop pm.dexopt.downgrade_after_inactive_days` days.
  *
+ * For some of the tests, the DeviceConfig flags inactive_app_threshold_days and
+ * downgrade_unused_apps_enabled are set. These turn on/off the downgrade unused apps feature for
+ * all devices and set the time threshold for unused apps.
+ *
  * For tests that require low storage, the phone is filled up.
  *
  * Run with "atest BackgroundDexOptServiceIntegrationTests".
@@ -80,10 +94,14 @@
             "pm.dexopt.downgrade_after_inactive_days", 0);
     // Needs to be between 1.0 and 2.0.
     private static final double LOW_STORAGE_MULTIPLIER = 1.5;
+    private static final int DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS = 15;
 
     // The file used to fill up storage.
     private File mBigFile;
 
+    @Rule
+    public ExpectedException mExpectedException = ExpectedException.none();
+
     // Remember start time.
     @BeforeClass
     public static void setUpAll() {
@@ -196,11 +214,27 @@
         logSpaceRemaining();
     }
 
+    private void fillUpStorageCompletely() throws IOException {
+        fillUpStorage((getStorageLowBytes()));
+    }
+
     // Fill up storage so that device is in low storage condition.
     private void fillUpToLowStorage() throws IOException {
         fillUpStorage((long) (getStorageLowBytes() * LOW_STORAGE_MULTIPLIER));
     }
 
+    private void setInactivePackageThreshold(int threshold) {
+        DeviceConfig.setProperty(
+                DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE,
+                "inactive_app_threshold_days", Integer.toString(threshold), false);
+    }
+
+    private void enableDowngradeFeature(boolean enabled) {
+        DeviceConfig.setProperty(
+                DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE,
+                "downgrade_unused_apps_enabled", Boolean.toString(enabled), false);
+    }
+
     // TODO(aeubanks): figure out how to get scheduled bg-dexopt to run
     private static void runBackgroundDexOpt() throws IOException {
         String result = runShellCommand("cmd package bg-dexopt-job " + PACKAGE_NAME);
@@ -244,7 +278,7 @@
 
     // Test that background dexopt under normal conditions succeeds.
     @Test
-    public void testBackgroundDexOpt() throws IOException {
+    public void testBackgroundDexOpt_normalConditions_dexOptSucceeds() throws IOException {
         // Set filter to quicken.
         compilePackageWithFilter(PACKAGE_NAME, "verify");
         Assert.assertEquals("verify", getCompilerFilter(PACKAGE_NAME));
@@ -257,17 +291,16 @@
 
     // Test that background dexopt under low storage conditions upgrades used packages.
     @Test
-    public void testBackgroundDexOptDowngradeSkipRecentlyUsedPackage() throws IOException {
+    public void testBackgroundDexOpt_lowStorage_usedPkgsUpgraded() throws IOException {
         // Should be less than DOWNGRADE_AFTER_DAYS.
         long deltaDays = DOWNGRADE_AFTER_DAYS - 1;
         try {
+            enableDowngradeFeature(false);
             // Set time to future.
             setTimeFutureDays(deltaDays);
-
             // Set filter to quicken.
             compilePackageWithFilter(PACKAGE_NAME, "quicken");
             Assert.assertEquals("quicken", getCompilerFilter(PACKAGE_NAME));
-
             // Fill up storage to trigger low storage threshold.
             fillUpToLowStorage();
 
@@ -282,18 +315,20 @@
     }
 
     // Test that background dexopt under low storage conditions downgrades unused packages.
+    // This happens if the system property pm.dexopt.downgrade_after_inactive_days is set
+    // (e.g. on Android Go devices).
     @Test
-    public void testBackgroundDexOptDowngradeSuccessful() throws IOException {
+    public void testBackgroundDexOpt_lowStorage_unusedPkgsDowngraded()
+            throws IOException {
         // Should be more than DOWNGRADE_AFTER_DAYS.
         long deltaDays = DOWNGRADE_AFTER_DAYS + 1;
         try {
+            enableDowngradeFeature(false);
             // Set time to future.
             setTimeFutureDays(deltaDays);
-
             // Set filter to quicken.
             compilePackageWithFilter(PACKAGE_NAME, "quicken");
             Assert.assertEquals("quicken", getCompilerFilter(PACKAGE_NAME));
-
             // Fill up storage to trigger low storage threshold.
             fillUpToLowStorage();
 
@@ -307,4 +342,134 @@
         }
     }
 
+    // Test that the background dexopt downgrades inactive packages when the downgrade feature is
+    // enabled.
+    @Test
+    public void testBackgroundDexOpt_downgradeFeatureEnabled_lowStorage_inactivePkgsDowngraded()
+            throws IOException {
+        // Should be more than DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS.
+        long deltaDays = DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS + 1;
+        try {
+            enableDowngradeFeature(true);
+            setInactivePackageThreshold(DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS);
+            // Set time to future.
+            setTimeFutureDays(deltaDays);
+            // Set filter to quicken.
+            compilePackageWithFilter(PACKAGE_NAME, "quicken");
+            Assert.assertEquals("quicken", getCompilerFilter(PACKAGE_NAME));
+            // Fill up storage to trigger low storage threshold.
+            fillUpToLowStorage();
+
+            runBackgroundDexOpt();
+
+            // Verify that downgrade is successful.
+            Assert.assertEquals(DOWNGRADE_COMPILER_FILTER, getCompilerFilter(PACKAGE_NAME));
+        } finally {
+            // Reset time.
+            setTimeFutureDays(-deltaDays);
+        }
+    }
+
+    // Test that the background dexopt upgrades used packages when the downgrade feature is enabled.
+    // This test doesn't fill the device storage completely, but to a multiplier of the low storage
+    // threshold and this is why apps can still be optimized.
+    @Test
+    public void testBackgroundDexOpt_downgradeFeatureEnabled_lowStorage_usedPkgsUpgraded()
+            throws IOException {
+        enableDowngradeFeature(true);
+        // Set filter to quicken.
+        compilePackageWithFilter(PACKAGE_NAME, "quicken");
+        Assert.assertEquals("quicken", getCompilerFilter(PACKAGE_NAME));
+        // Fill up storage to trigger low storage threshold.
+        fillUpToLowStorage();
+
+        runBackgroundDexOpt();
+
+        /// Verify that bg-dexopt is successful in upgrading the used packages.
+        Assert.assertEquals(BG_DEXOPT_COMPILER_FILTER, getCompilerFilter(PACKAGE_NAME));
+    }
+
+    // Test that the background dexopt fails and doesn't change the compilation filter of used
+    // packages when the downgrade feature is enabled and the storage is filled up completely.
+    // The bg-dexopt shouldn't optimise nor downgrade these packages.
+    @Test
+    public void testBackgroundDexOpt_downgradeFeatureEnabled_fillUpStorageCompletely_dexOptFails()
+            throws IOException {
+        enableDowngradeFeature(true);
+        String previousCompilerFilter = getCompilerFilter(PACKAGE_NAME);
+
+        // Fill up storage completely, without using a multiplier for the low storage threshold.
+        fillUpStorageCompletely();
+
+        // When the bg dexopt runs with the storage filled up completely, it will fail.
+        mExpectedException.expect(IllegalStateException.class);
+        runBackgroundDexOpt();
+
+        /// Verify that bg-dexopt doesn't change the compilation filter of used apps.
+        Assert.assertEquals(previousCompilerFilter, getCompilerFilter(PACKAGE_NAME));
+    }
+
+    // Test that the background dexopt upgrades the unused packages when the downgrade feature is
+    // on if the device is not low on storage.
+    @Test
+    public void testBackgroundDexOpt_downgradeFeatureEnabled_notLowStorage_unusedPkgsUpgraded()
+            throws IOException {
+        // Should be more than DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS.
+        long deltaDays = DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS + 1;
+        try {
+            enableDowngradeFeature(true);
+            setInactivePackageThreshold(DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS);
+            // Set time to future.
+            setTimeFutureDays(deltaDays);
+            // Set filter to quicken.
+            compilePackageWithFilter(PACKAGE_NAME, "quicken");
+            Assert.assertEquals("quicken", getCompilerFilter(PACKAGE_NAME));
+
+            runBackgroundDexOpt();
+
+            // Verify that bg-dexopt is successful in upgrading the unused packages when the device
+            // is not low on storage.
+            Assert.assertEquals(BG_DEXOPT_COMPILER_FILTER, getCompilerFilter(PACKAGE_NAME));
+        } finally {
+            // Reset time.
+            setTimeFutureDays(-deltaDays);
+        }
+    }
+
+    // Test that when an unused package (which was downgraded) is used again, it's re-optimized when
+    // bg-dexopt runs again.
+    @Test
+    public void testBackgroundDexOpt_downgradeFeatureEnabled_downgradedPkgsUpgradedAfterUse()
+            throws IOException {
+        // Should be more than DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS.
+        long deltaDays = DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS + 1;
+        try {
+            enableDowngradeFeature(true);
+            setInactivePackageThreshold(DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS);
+            // Set time to future.
+            setTimeFutureDays(deltaDays);
+            // Fill up storage to trigger low storage threshold.
+            fillUpToLowStorage();
+            // Set filter to quicken.
+            compilePackageWithFilter(PACKAGE_NAME, "quicken");
+            Assert.assertEquals("quicken", getCompilerFilter(PACKAGE_NAME));
+
+            runBackgroundDexOpt();
+
+            // Verify that downgrade is successful.
+            Assert.assertEquals(DOWNGRADE_COMPILER_FILTER, getCompilerFilter(PACKAGE_NAME));
+
+            // Reset time.
+            setTimeFutureDays(-deltaDays);
+            deltaDays = 0;
+            runBackgroundDexOpt();
+
+            // Verify that bg-dexopt is successful in upgrading the unused packages that were used
+            // again.
+            Assert.assertEquals(BG_DEXOPT_COMPILER_FILTER, getCompilerFilter(PACKAGE_NAME));
+        } finally {
+            // Reset time.
+            setTimeFutureDays(-deltaDays);
+        }
+    }
 }
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index 720c1af..ed8f272 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -19,6 +19,8 @@
 import static com.android.cts.install.lib.InstallUtils.processUserData;
 import static com.android.cts.rollback.lib.RollbackInfoSubject.assertThat;
 import static com.android.cts.rollback.lib.RollbackUtils.getUniqueRollbackInfoForPackage;
+import static com.android.cts.rollback.lib.RollbackUtils.waitForAvailableRollback;
+import static com.android.cts.rollback.lib.RollbackUtils.waitForUnavailableRollback;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -118,8 +120,7 @@
             }
 
             // The app should not be available for rollback.
-            assertThat(
-                getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TestApp.A)).isNull();
+            waitForUnavailableRollback(TestApp.A);
 
             // There should be no recently committed rollbacks for this package.
             assertThat(getUniqueRollbackInfoForPackage(
@@ -134,9 +135,7 @@
             assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
 
             // The app should now be available for rollback.
-            RollbackInfo available = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TestApp.A);
-            assertThat(available).isNotNull();
+            RollbackInfo available = waitForAvailableRollback(TestApp.A);
             assertThat(available).isNotStaged();
             assertThat(available).packagesContainsExactly(
                     Rollback.from(TestApp.A2).to(TestApp.A1));
@@ -197,14 +196,12 @@
             assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
 
             // Both test apps should now be available for rollback.
-            RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TestApp.A);
+            RollbackInfo rollbackA = waitForAvailableRollback(TestApp.A);
             assertThat(rollbackA).isNotNull();
             assertThat(rollbackA).packagesContainsExactly(
                     Rollback.from(TestApp.A2).to(TestApp.A1));
 
-            RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TestApp.B);
+            RollbackInfo rollbackB = waitForAvailableRollback(TestApp.B);
             assertThat(rollbackB).isNotNull();
             assertThat(rollbackB).packagesContainsExactly(
                     Rollback.from(TestApp.B2).to(TestApp.B1));
@@ -213,14 +210,12 @@
             rm.reloadPersistedData();
 
             // The apps should still be available for rollback.
-            rollbackA = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TestApp.A);
+            rollbackA = waitForAvailableRollback(TestApp.A);
             assertThat(rollbackA).isNotNull();
             assertThat(rollbackA).packagesContainsExactly(
                     Rollback.from(TestApp.A2).to(TestApp.A1));
 
-            rollbackB = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TestApp.B);
+            rollbackB = waitForAvailableRollback(TestApp.B);
             assertThat(rollbackB).isNotNull();
             assertThat(rollbackB).packagesContainsExactly(
                     Rollback.from(TestApp.B2).to(TestApp.B1));
@@ -255,15 +250,13 @@
             assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
 
             // The app should now be available for rollback.
-            RollbackInfo availableA = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TestApp.A);
+            RollbackInfo availableA = waitForAvailableRollback(TestApp.A);
             assertThat(availableA).isNotNull();
             assertThat(availableA).packagesContainsExactly(
                     Rollback.from(TestApp.A2).to(TestApp.A1),
                     Rollback.from(TestApp.B2).to(TestApp.B1));
 
-            RollbackInfo availableB = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TestApp.B);
+            RollbackInfo availableB = waitForAvailableRollback(TestApp.B);
             assertThat(availableB).isNotNull();
             assertThat(availableB).packagesContainsExactly(
                     Rollback.from(TestApp.A2).to(TestApp.A1),
@@ -276,13 +269,13 @@
             rm.reloadPersistedData();
 
             // The apps should still be available for rollback.
-            availableA = getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TestApp.A);
+            availableA = waitForAvailableRollback(TestApp.A);
             assertThat(availableA).isNotNull();
             assertThat(availableA).packagesContainsExactly(
                     Rollback.from(TestApp.A2).to(TestApp.A1),
                     Rollback.from(TestApp.B2).to(TestApp.B1));
 
-            availableB = getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TestApp.B);
+            availableB = waitForAvailableRollback(TestApp.B);
             assertThat(availableB).isNotNull();
             assertThat(availableB).packagesContainsExactly(
                     Rollback.from(TestApp.A2).to(TestApp.A1),
@@ -334,8 +327,7 @@
             assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
 
             // The app should now be available for rollback.
-            RollbackInfo available = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TestApp.A);
+            RollbackInfo available = waitForAvailableRollback(TestApp.A);
             assertThat(available).isNotNull();
 
             // Roll back the app.
@@ -405,13 +397,11 @@
 
             // Check that the rollback data has not expired
             Thread.sleep(1000);
-            RollbackInfo rollback = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TestApp.A);
-            assertThat(rollback).isNotNull();
+            RollbackInfo rollback = waitForAvailableRollback(TestApp.A);
             assertThat(rollback).packagesContainsExactly(
                     Rollback.from(TestApp.A2).to(TestApp.A1));
 
-            // Give it a little more time, but still not the long enough to expire
+            // Give it a little more time, but still not long enough to expire
             Thread.sleep(expirationTime / 2);
             rollback = getUniqueRollbackInfoForPackage(
                     rm.getAvailableRollbacks(), TestApp.A);
@@ -536,9 +526,7 @@
             assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
 
             // The app should now be available for rollback.
-            RollbackInfo rollback = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TestApp.A);
-            assertThat(rollback).isNotNull();
+            RollbackInfo rollback = waitForAvailableRollback(TestApp.A);
             assertThat(rollback).packagesContainsExactly(
                     Rollback.from(TestApp.A2).to(TestApp.A1));
 
@@ -570,9 +558,7 @@
             Install.single(TestApp.A2).setEnableRollback().commit();
             processUserData(TestApp.A);
 
-            RollbackManager rm = RollbackUtils.getRollbackManager();
-            RollbackInfo rollback = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TestApp.A);
+            RollbackInfo rollback = waitForAvailableRollback(TestApp.A);
             RollbackUtils.rollback(rollback.getRollbackId());
             processUserData(TestApp.A);
         } finally {
@@ -598,10 +584,7 @@
             Install.single(TestApp.ASplit2).setEnableRollback().commit();
             processUserData(TestApp.A);
 
-            RollbackManager rm = RollbackUtils.getRollbackManager();
-            RollbackInfo rollback = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TestApp.A);
-            assertThat(rollback).isNotNull();
+            RollbackInfo rollback = waitForAvailableRollback(TestApp.A);
             RollbackUtils.rollback(rollback.getRollbackId());
             processUserData(TestApp.A);
         } finally {
@@ -644,7 +627,6 @@
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
                     Manifest.permission.TEST_MANAGE_ROLLBACKS);
-            RollbackManager rm = RollbackUtils.getRollbackManager();
 
             // Prep installation of the test apps.
             Uninstall.packages(TestApp.A);
@@ -659,15 +641,11 @@
 
             // Both test apps should now be available for rollback, and the
             // RollbackInfo returned for the rollbacks should be correct.
-            RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TestApp.A);
-            assertThat(rollbackA).isNotNull();
+            RollbackInfo rollbackA = waitForAvailableRollback(TestApp.A);
             assertThat(rollbackA).packagesContainsExactly(
                     Rollback.from(TestApp.A2).to(TestApp.A1));
 
-            RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TestApp.B);
-            assertThat(rollbackB).isNotNull();
+            RollbackInfo rollbackB = waitForAvailableRollback(TestApp.B);
             assertThat(rollbackB).packagesContainsExactly(
                     Rollback.from(TestApp.B2).to(TestApp.B1));
 
@@ -822,8 +800,7 @@
             assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
 
             // TestApp.A should now be available for rollback.
-            RollbackInfo rollback = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TestApp.A);
+            RollbackInfo rollback = waitForAvailableRollback(TestApp.A);
             assertThat(rollback).isNotNull();
             assertThat(rollback).packagesContainsExactly(
                     Rollback.from(TestApp.A2).to(TestApp.A1),
@@ -938,7 +915,6 @@
                     Manifest.permission.TEST_MANAGE_ROLLBACKS,
                     Manifest.permission.FORCE_STOP_PACKAGES,
                     Manifest.permission.RESTART_PACKAGES);
-            RollbackManager rm = RollbackUtils.getRollbackManager();
 
             // Prep installation of the test apps.
             Uninstall.packages(TestApp.A, TestApp.B);
@@ -952,13 +928,11 @@
 
             // Both test apps should now be available for rollback, and the
             // targetPackage returned for rollback should be correct.
-            RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TestApp.A);
+            RollbackInfo rollbackA = waitForAvailableRollback(TestApp.A);
             assertThat(rollbackA).packagesContainsExactly(
                     Rollback.from(TestApp.A2).to(TestApp.A1));
 
-            RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TestApp.B);
+            RollbackInfo rollbackB = waitForAvailableRollback(TestApp.B);
             assertThat(rollbackB).packagesContainsExactly(
                     Rollback.from(TestApp.B2).to(TestApp.B1));
 
@@ -1002,8 +976,7 @@
             Install.single(TestApp.A2).setEnableRollback().commit();
             assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
 
-            RollbackInfo rollback = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TestApp.A);
+            RollbackInfo rollback = waitForAvailableRollback(TestApp.A);
             assertThat(rollback).packagesContainsExactly(
                     Rollback.from(TestApp.A2).to(TestApp.A1));
 
@@ -1047,6 +1020,7 @@
 
             Uninstall.packages(TestApp.A);
             Install.single(TestApp.A1).commit();
+            waitForUnavailableRollback(TestApp.A);
 
             // Block the RollbackManager to make extra sure it will not be
             // able to enable the rollback in time.
@@ -1055,6 +1029,10 @@
 
             assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
 
+            // Give plenty of time for RollbackManager to unblock and attempt
+            // to make the rollback available before asserting that the
+            // rollback was not made available.
+            Thread.sleep(TimeUnit.SECONDS.toMillis(2));
             assertThat(
                 getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TestApp.A)).isNull();
         } finally {
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index f3c735c..6ae639a 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -5692,7 +5692,6 @@
         String[] values = tcpBufferSizes.split(",");
         String rmemValues = String.join(" ", values[0], values[1], values[2]);
         String wmemValues = String.join(" ", values[3], values[4], values[5]);
-        waitForIdle();
         verify(mMockNetd, atLeastOnce()).setTcpRWmemorySize(rmemValues, wmemValues);
         reset(mMockNetd);
     }
@@ -5700,18 +5699,32 @@
     @Test
     public void testTcpBufferReset() throws Exception {
         final String testTcpBufferSizes = "1,2,3,4,5,6";
+        final NetworkRequest networkRequest = new NetworkRequest.Builder()
+                .addTransportType(TRANSPORT_CELLULAR)
+                .addCapability(NET_CAPABILITY_INTERNET)
+                .build();
+        final TestNetworkCallback networkCallback = new TestNetworkCallback();
+        mCm.registerNetworkCallback(networkRequest, networkCallback);
 
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         reset(mMockNetd);
         // Switching default network updates TCP buffer sizes.
         mCellNetworkAgent.connect(false);
+        networkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
         verifyTcpBufferSizeChange(ConnectivityService.DEFAULT_TCP_BUFFER_SIZES);
 
         // Change link Properties should have updated tcp buffer size.
         LinkProperties lp = new LinkProperties();
         lp.setTcpBufferSizes(testTcpBufferSizes);
         mCellNetworkAgent.sendLinkProperties(lp);
+        networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
         verifyTcpBufferSizeChange(testTcpBufferSizes);
+
+        // Clean up.
+        mCellNetworkAgent.disconnect();
+        networkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
+        networkCallback.assertNoCallback();
+        mCm.unregisterNetworkCallback(networkCallback);
     }
 
     @Test
diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java
index 6ce2121..6a03c73 100644
--- a/wifi/java/android/net/wifi/RttManager.java
+++ b/wifi/java/android/net/wifi/RttManager.java
@@ -211,6 +211,7 @@
         /** Draft 11mc version supported, including major and minor version. e.g, draft 4.3 is 43 */
         public int mcVersion;
 
+        @NonNull
         @Override
         public String toString() {
             StringBuffer sb = new StringBuffer();
@@ -1130,6 +1131,7 @@
          */
         public int preamble;
 
+        @NonNull
         @Override
         public String toString() {
             StringBuilder builder = new StringBuilder();
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index f2ae447..eb5a717 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.content.pm.PackageManager;
@@ -510,6 +511,12 @@
     public String preSharedKey;
 
     /**
+     * Optional SAE Password Id for use with WPA3-SAE. It is an ASCII string.
+     * @hide
+     */
+    public @Nullable String saePasswordId;
+
+    /**
      * Four WEP keys. For each of the four values, provide either an ASCII
      * string enclosed in double quotation marks (e.g., {@code "abcdef"}),
      * a string of hex digits (e.g., {@code 0102030405}), or an empty string
@@ -2004,6 +2011,9 @@
             sbuf.append('*');
         }
 
+        sbuf.append('\n').append(" SAE Password Id: ");
+        sbuf.append(this.saePasswordId);
+
         sbuf.append("\nEnterprise config:\n");
         sbuf.append(enterpriseConfig);
 
@@ -2372,6 +2382,7 @@
             providerFriendlyName = source.providerFriendlyName;
             isHomeProviderNetwork = source.isHomeProviderNetwork;
             preSharedKey = source.preSharedKey;
+            saePasswordId = source.saePasswordId;
 
             mNetworkSelectionStatus.copy(source.getNetworkSelectionStatus());
             apBand = source.apBand;
@@ -2462,6 +2473,7 @@
             dest.writeLong(roamingConsortiumId);
         }
         dest.writeString(preSharedKey);
+        dest.writeString(saePasswordId);
         for (String wepKey : wepKeys) {
             dest.writeString(wepKey);
         }
@@ -2537,6 +2549,7 @@
                     config.roamingConsortiumIds[i] = in.readLong();
                 }
                 config.preSharedKey = in.readString();
+                config.saePasswordId = in.readString();
                 for (int i = 0; i < config.wepKeys.length; i++) {
                     config.wepKeys[i] = in.readString();
                 }
@@ -2608,6 +2621,7 @@
         out.writeInt(apBand);
         out.writeInt(apChannel);
         BackupUtils.writeString(out, preSharedKey);
+        BackupUtils.writeString(out, saePasswordId);
         out.writeInt(getAuthType());
         out.writeBoolean(hiddenSSID);
         return baos.toByteArray();
@@ -2631,6 +2645,7 @@
         config.apBand = in.readInt();
         config.apChannel = in.readInt();
         config.preSharedKey = BackupUtils.readString(in);
+        config.saePasswordId = BackupUtils.readString(in);
         config.allowedKeyManagement.set(in.readInt());
         if (version >= 3) {
             config.hiddenSSID = in.readBoolean();
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index e9c24cd..6bf7bfb9 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -634,10 +634,19 @@
      */
     public static final int SAP_START_FAILURE_NO_CHANNEL = 1;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"IFACE_IP_MODE_"}, value = {
+            IFACE_IP_MODE_UNSPECIFIED,
+            IFACE_IP_MODE_CONFIGURATION_ERROR,
+            IFACE_IP_MODE_TETHERED,
+            IFACE_IP_MODE_LOCAL_ONLY})
+    public @interface IfaceIpMode {}
+
     /**
      * Interface IP mode unspecified.
      *
-     * @see updateInterfaceIpState(String, int)
+     * @see #updateInterfaceIpState(String, int)
      *
      * @hide
      */
@@ -646,7 +655,7 @@
     /**
      * Interface IP mode for configuration error.
      *
-     * @see updateInterfaceIpState(String, int)
+     * @see #updateInterfaceIpState(String, int)
      *
      * @hide
      */
@@ -655,7 +664,7 @@
     /**
      * Interface IP mode for tethering.
      *
-     * @see updateInterfaceIpState(String, int)
+     * @see #updateInterfaceIpState(String, int)
      *
      * @hide
      */
@@ -664,7 +673,7 @@
     /**
      * Interface IP mode for Local Only Hotspot.
      *
-     * @see updateInterfaceIpState(String, int)
+     * @see #updateInterfaceIpState(String, int)
      *
      * @hide
      */
@@ -2670,9 +2679,9 @@
     /**
      * Call allowing ConnectivityService to update WifiService with interface mode changes.
      *
-     * The possible modes include: {@link IFACE_IP_MODE_TETHERED},
-     *                             {@link IFACE_IP_MODE_LOCAL_ONLY},
-     *                             {@link IFACE_IP_MODE_CONFIGURATION_ERROR}
+     * The possible modes include: {@link #IFACE_IP_MODE_TETHERED},
+     *                             {@link #IFACE_IP_MODE_LOCAL_ONLY},
+     *                             {@link #IFACE_IP_MODE_CONFIGURATION_ERROR}
      *
      * @param ifaceName String name of the updated interface
      * @param mode int representing the new mode
@@ -3397,6 +3406,7 @@
 
         private final CloseGuard mCloseGuard = CloseGuard.get();
         private final WifiConfiguration mConfig;
+        private boolean mClosed = false;
 
         /** @hide */
         @VisibleForTesting
@@ -3412,8 +3422,13 @@
         @Override
         public void close() {
             try {
-                stopLocalOnlyHotspot();
-                mCloseGuard.close();
+                synchronized (mLock) {
+                    if (!mClosed) {
+                        mClosed = true;
+                        stopLocalOnlyHotspot();
+                        mCloseGuard.close();
+                    }
+                }
             } catch (Exception e) {
                 Log.e(TAG, "Failed to stop Local Only Hotspot.");
             }
diff --git a/wifi/java/android/net/wifi/WifiNetworkConnectionStatistics.java b/wifi/java/android/net/wifi/WifiNetworkConnectionStatistics.java
index 8262a7a..95b2e77 100644
--- a/wifi/java/android/net/wifi/WifiNetworkConnectionStatistics.java
+++ b/wifi/java/android/net/wifi/WifiNetworkConnectionStatistics.java
@@ -16,8 +16,8 @@
 
 package android.net.wifi;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
-
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -39,7 +39,7 @@
 
     public WifiNetworkConnectionStatistics() { }
 
-
+    @NonNull
     @Override
     public String toString() {
         StringBuilder sbuf = new StringBuilder();
diff --git a/wifi/java/android/net/wifi/hotspot2/OsuProvider.java b/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
index 57dff9d..a32bd54 100644
--- a/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
+++ b/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
@@ -16,6 +16,7 @@
 
 package android.net.wifi.hotspot2;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.graphics.drawable.Icon;
@@ -219,7 +220,7 @@
     }
 
     @Override
-    public boolean equals(Object thatObject) {
+    public boolean equals(@Nullable Object thatObject) {
         if (this == thatObject) {
             return true;
         }
@@ -246,6 +247,7 @@
                 mServerUri, mNetworkAccessIdentifier, mMethodList);
     }
 
+    @NonNull
     @Override
     public String toString() {
         return "OsuProvider{mOsuSsid=" + mOsuSsid
diff --git a/wifi/java/android/net/wifi/rtt/RangingRequest.java b/wifi/java/android/net/wifi/rtt/RangingRequest.java
index 70af03e..318efa6 100644
--- a/wifi/java/android/net/wifi/rtt/RangingRequest.java
+++ b/wifi/java/android/net/wifi/rtt/RangingRequest.java
@@ -17,6 +17,7 @@
 package android.net.wifi.rtt;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.net.MacAddress;
 import android.net.wifi.ScanResult;
@@ -245,7 +246,7 @@
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (this == o) {
             return true;
         }
diff --git a/wifi/java/android/net/wifi/rtt/ResponderConfig.java b/wifi/java/android/net/wifi/rtt/ResponderConfig.java
index e6ae483..64dfc34 100644
--- a/wifi/java/android/net/wifi/rtt/ResponderConfig.java
+++ b/wifi/java/android/net/wifi/rtt/ResponderConfig.java
@@ -21,6 +21,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.net.MacAddress;
 import android.net.wifi.ScanResult;
@@ -443,7 +444,7 @@
     };
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         if (this == o) {
             return true;
         }