Merge "Move transport out of system server."
diff --git a/Android.bp b/Android.bp
index cb7f7a2..faad6f3 100644
--- a/Android.bp
+++ b/Android.bp
@@ -77,6 +77,7 @@
         "core/java/android/app/ISearchManager.aidl",
         "core/java/android/app/ISearchManagerCallback.aidl",
         "core/java/android/app/IServiceConnection.aidl",
+        "core/java/android/app/ISmsAppService.aidl",
         "core/java/android/app/IStopUserCallback.aidl",
         "core/java/android/app/job/IJobCallback.aidl",
         "core/java/android/app/job/IJobScheduler.aidl",
@@ -151,8 +152,8 @@
         ":libcamera_client_framework_aidl",
         "core/java/android/hardware/IConsumerIrService.aidl",
         "core/java/android/hardware/ISerialManager.aidl",
-        "core/java/android/hardware/biometrics/IBiometricPromptService.aidl",
-        "core/java/android/hardware/biometrics/IBiometricPromptServiceReceiver.aidl",
+        "core/java/android/hardware/biometrics/IBiometricService.aidl",
+        "core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl",
         "core/java/android/hardware/biometrics/IBiometricPromptReceiver.aidl",
         "core/java/android/hardware/biometrics/IBiometricServiceLockoutResetCallback.aidl",
         "core/java/android/hardware/display/IDisplayManager.aidl",
@@ -368,6 +369,7 @@
         "core/java/com/android/internal/app/IAppOpsService.aidl",
         "core/java/com/android/internal/app/IBatteryStats.aidl",
         "core/java/com/android/internal/app/ISoundTriggerService.aidl",
+        "core/java/com/android/internal/app/IVoiceActionCheckCallback.aidl",
         "core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl",
         "core/java/com/android/internal/app/IVoiceInteractionSessionListener.aidl",
         "core/java/com/android/internal/app/IVoiceInteractionSessionShowCallback.aidl",
@@ -514,11 +516,14 @@
         "telephony/java/android/telephony/ims/aidl/IImsSmsListener.aidl",
         "telephony/java/android/telephony/mbms/IMbmsDownloadSessionCallback.aidl",
         "telephony/java/android/telephony/mbms/IMbmsStreamingSessionCallback.aidl",
+        "telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl",
         "telephony/java/android/telephony/mbms/IDownloadStatusListener.aidl",
         "telephony/java/android/telephony/mbms/IDownloadProgressListener.aidl",
         "telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl",
+        "telephony/java/android/telephony/mbms/IGroupCallCallback.aidl",
         "telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl",
         "telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl",
+        "telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl",
         "telephony/java/android/telephony/INetworkService.aidl",
         "telephony/java/android/telephony/INetworkServiceCallback.aidl",
         "telephony/java/com/android/ims/internal/IImsCallSession.aidl",
@@ -702,7 +707,6 @@
 
     // Loaded with System.loadLibrary by android.view.textclassifier
     required: [
-        "libtextclassifier",
         "libmedia2_jni",
     ],
 
@@ -806,12 +810,16 @@
 java_library {
     name: "ext",
     installable: true,
-    no_framework_libs: true,
+    sdk_version: "core_current",
     static_libs: [
         "libphonenumber-platform",
         "nist-sip",
         "tagsoup",
         "rappor",
+        "libtextclassifier-java",
+    ],
+    required: [
+        "libtextclassifier",
     ],
     dxflags: ["--core-library"],
 }
@@ -1084,53 +1092,63 @@
      "-federate SupportLib https://developer.android.com " +
      "-federationapi SupportLib $(location current/support-api.txt) "
 
-doc_defaults {
-    name: "api-stubs-default",
-    srcs: [
-        ":opt-telephony-srcs",
-        ":opt-net-voip-srcs",
-        ":openjdk_javadoc_files",
-        ":non_openjdk_javadoc_files",
-        ":android_icu4j_src_files_for_docs",
-    ],
-    srcs_lib: "framework",
-    srcs_lib_whitelist_dirs: frameworks_base_subdirs,
-    srcs_lib_whitelist_pkgs: packages_to_document,
-    libs: [
-        "core-oj",
-        "core-libart",
-        "conscrypt",
-        "bouncycastle",
-        "okhttp",
-        "ext",
-        "framework",
-        "voip-common",
-        "android.test.mock.impl",
-    ],
-    local_sourcepaths: frameworks_base_subdirs,
-    html_dirs: [
-        "docs/html",
-    ],
-    knowntags: [
-        "docs/knowntags.txt",
-        ":known-oj-tags",
-    ],
-    custom_template: "droiddoc-templates-sdk",
-    hdf: [
-        "dac true",
-        "sdk.codename O",
-        "sdk.preview.version 1",
-        "sdk.version 7.0",
-        "sdk.rel.id 1",
-        "sdk.preview 0",
-    ],
-    resourcesdir: "docs/html/reference/images",
-    resourcesoutdir: "reference/android/images",
-    installable: false,
-}
+framework_docs_only_args = " -android -manifest $(location core/res/AndroidManifest.xml) " +
+     "-overview $(location core/java/overview.html) " +
+     // Federate Support Library references against local API file.
+     "-federate SupportLib https://developer.android.com " +
+     "-federationapi SupportLib $(location current/support-api.txt) "
 
-doc_defaults {
-    name: "framework-docs-default",
+framework_docs_only_libs = [
+    "conscrypt",
+    "bouncycastle",
+    "voip-common",
+    "android.test.mock",
+    "android-support-annotations",
+    "android-support-compat",
+    "android-support-core-ui",
+    "android-support-core-utils",
+    "android-support-customtabs",
+    "android-support-design",
+    "android-support-dynamic-animation",
+    "android-support-exifinterface",
+    "android-support-fragment",
+    "android-support-media-compat",
+    "android-support-percent",
+    "android-support-recommendation",
+    "android-support-transition",
+    "android-support-tv-provider",
+    "android-support-v7-cardview",
+    "android-support-v7-gridlayout",
+    "android-support-v7-mediarouter",
+    "android-support-v7-palette",
+    "android-support-v7-preference",
+    "android-support-v13",
+    "android-support-v14-preference",
+    "android-support-v17-leanback",
+    "android-support-v17-preference-leanback",
+    "android-support-wear",
+    "android-support-vectordrawable",
+    "android-support-animatedvectordrawable",
+    "android-support-v7-appcompat",
+    "android-support-v7-recyclerview",
+    "android-support-emoji",
+    "android-support-emoji-appcompat",
+    "android-support-emoji-bundled",
+    "android-support-v8-renderscript",
+    "android-support-multidex",
+    "android-support-multidex-instrumentation",
+]
+
+metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.xml) " +
+    "--hide-package com.android.okhttp " +
+    "--hide-package com.android.org.conscrypt --hide-package com.android.server " +
+    "--hide RequiresPermission " +
+    "--hide MissingPermission --hide BroadcastBehavior " +
+    "--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " +
+    "--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo"
+
+stubs_defaults {
+    name: "framework-doc-stubs-default",
     srcs: [
         "test-base/src/**/*.java",
         ":opt-telephony-srcs",
@@ -1144,47 +1162,25 @@
     srcs_lib: "framework",
     srcs_lib_whitelist_dirs: frameworks_base_subdirs,
     srcs_lib_whitelist_pkgs: packages_to_document,
-    libs: [
-        "conscrypt",
-        "bouncycastle",
-        "voip-common",
-        "android.test.mock",
-        "android-support-annotations",
-        "android-support-compat",
-        "android-support-core-ui",
-        "android-support-core-utils",
-        "android-support-customtabs",
-        "android-support-design",
-        "android-support-dynamic-animation",
-        "android-support-exifinterface",
-        "android-support-fragment",
-        "android-support-media-compat",
-        "android-support-percent",
-        "android-support-recommendation",
-        "android-support-transition",
-        "android-support-tv-provider",
-        "android-support-v7-cardview",
-        "android-support-v7-gridlayout",
-        "android-support-v7-mediarouter",
-        "android-support-v7-palette",
-        "android-support-v7-preference",
-        "android-support-v13",
-        "android-support-v14-preference",
-        "android-support-v17-leanback",
-        "android-support-v17-preference-leanback",
-        "android-support-wear",
-        "android-support-vectordrawable",
-        "android-support-animatedvectordrawable",
-        "android-support-v7-appcompat",
-        "android-support-v7-recyclerview",
-        "android-support-emoji",
-        "android-support-emoji-appcompat",
-        "android-support-emoji-bundled",
-        "android-support-v8-renderscript",
-        "android-support-multidex",
-        "android-support-multidex-instrumentation",
-    ],
+    libs: framework_docs_only_libs,
     local_sourcepaths: frameworks_base_subdirs,
+    create_doc_stubs: true,
+    annotations_enabled: true,
+    api_levels_annotations_enabled: true,
+    api_levels_annotations_dirs: [
+        "sdk-dir",
+        "api-versions-jars-dir",
+    ],
+    previous_api: ":last-released-public-api",
+    merge_annotations_dirs: [
+        "metalava-manual",
+        "ojluni-annotated-sdk-stubs",
+    ],
+}
+
+doc_defaults {
+    name: "framework-docs-default",
+    libs: framework_docs_only_libs,
     html_dirs: [
         "docs/html",
     ],
@@ -1205,22 +1201,12 @@
     ],
     arg_files: [
         "core/res/AndroidManifest.xml",
-        ":api-version-xml",
         "core/java/overview.html",
         ":current-support-api",
-        "api/current.txt",
     ],
     create_stubs: false,
 }
 
-metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.xml) " +
-    "--hide-package com.android.okhttp " +
-    "--hide-package com.android.org.conscrypt --hide-package com.android.server " +
-    "--hide RequiresPermission " +
-    "--hide MissingPermission --hide BroadcastBehavior " +
-    "--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " +
-    "--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo"
-
 stubs_defaults {
     name: "metalava-api-stubs-default",
     srcs: [
@@ -1250,52 +1236,92 @@
     previous_api: ":last-released-public-api",
     merge_annotations_dirs: [
         "metalava-manual",
-        "ojluni-annotated-stubs",
+        "ojluni-annotated-sdk-stubs",
     ],
+    api_levels_annotations_enabled: true,
+    api_levels_annotations_dirs: [
+        "sdk-dir",
+        "api-versions-jars-dir",
+    ],
+}
+
+droidstubs {
+    name: "framework-doc-stubs",
+    defaults: ["framework-doc-stubs-default"],
+    arg_files: [
+        "core/res/AndroidManifest.xml",
+    ],
+    args: metalava_framework_docs_args,
+}
+
+droidstubs {
+    name: "framework-doc-system-stubs",
+    defaults: ["framework-doc-stubs-default"],
+    arg_files: [
+        "core/res/AndroidManifest.xml",
+    ],
+    args: metalava_framework_docs_args + " --show-annotation android.annotation.SystemApi ",
 }
 
 droiddoc {
     name: "doc-comment-check-docs",
     defaults: ["framework-docs-default"],
-    args: framework_docs_args + " -referenceonly -parsecomments",
+    srcs: [
+        ":framework-doc-stubs",
+    ],
+    args: framework_docs_only_args + " -referenceonly -parsecomments",
     installable: false,
 }
 
 droiddoc {
     name: "offline-sdk-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-stubs",
+    ],
     hdf: [
         "android.whichdoc offline",
     ],
     proofread_file: "offline-sdk-docs-proofrerad.txt",
-    args: framework_docs_args + " -offlinemode -title \"Android SDK\"",
+    args: framework_docs_only_args + " -offlinemode -title \"Android SDK\"",
     write_sdk_values: true,
     static_doc_index_redirect: "docs/docs-preview-index.html",
 }
 
 droiddoc {
+    // Please sync with android-api-council@ before making any changes for the name property below.
+    // Since there's cron jobs that fetch offline-sdk-referenceonly-docs-docs.zip periodically.
+    // See b/116221385 for reference.
     name: "offline-sdk-referenceonly-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-stubs",
+    ],
     hdf: [
         "android.whichdoc offline",
     ],
     proofread_file: "offline-sdk-referenceonly-docs-proofrerad.txt",
-    args: framework_docs_args + " -offlinemode -title \"Android SDK\" -referenceonly",
+    args: framework_docs_only_args + " -offlinemode -title \"Android SDK\" -referenceonly",
     write_sdk_values: true,
     static_doc_index_redirect: "docs/docs-documentation-redirect.html",
     static_doc_properties: "docs/source.properties",
 }
 
 droiddoc {
+    // Please sync with android-api-council@ before making any changes for the name property below.
+    // Since there's cron jobs that fetch offline-system-sdk-referenceonly-docs-docs.zip periodically.
+    // See b/116221385 for reference.
     name: "offline-system-sdk-referenceonly-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-system-stubs",
+    ],
     hdf: [
         "android.whichdoc offline",
     ],
     proofread_file: "offline-system-sdk-referenceonly-docs-proofrerad.txt",
-    args: framework_docs_args + " -hide 101 -hide 104 -hide 108" +
-          " -showAnnotation android.annotation.SystemApi " +
-          " -offlinemode -title \"Android System SDK\" -referenceonly",
+    args: framework_docs_only_args  + " -hide 101 -hide 104 -hide 108" +
+        " -offlinemode -title \"Android System SDK\" -referenceonly",
     write_sdk_values: true,
     static_doc_index_redirect: "docs/docs-documentation-redirect.html",
     static_doc_properties: "docs/source.properties",
@@ -1304,12 +1330,15 @@
 droiddoc {
     name: "online-sdk-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-stubs",
+    ],
     hdf: [
         "android.whichdoc online",
         "android.hasSamples true",
     ],
     proofread_file: "online-sdk-docs-proofrerad.txt",
-    args: framework_docs_args +
+    args: framework_docs_only_args  +
         " -toroot / -samplegroup Admin " +
         " -samplegroup Background " +
         " -samplegroup Connectivity " +
@@ -1330,14 +1359,16 @@
 droiddoc {
     name: "online-system-api-sdk-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-system-stubs",
+    ],
     hdf: [
         "android.whichdoc online",
         "android.hasSamples true",
     ],
     proofread_file: "online-system-api-sdk-docs-proofrerad.txt",
-    args: framework_docs_args +
+    args: framework_docs_only_args +
         " -referenceonly " +
-        " -showAnnotation android.annotation.SystemApi " +
         " -title \"Android SDK - Including system APIs.\" " +
         " -hide 101 " +
         " -hide 104 " +
@@ -1363,12 +1394,15 @@
 droiddoc {
     name: "ds-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-stubs",
+    ],
     hdf: [
         "android.whichdoc online",
         "android.hasSamples true",
     ],
     proofread_file: "ds-docs-proofrerad.txt",
-    args: framework_docs_args +
+    args: framework_docs_only_args +
         " -toroot / -samplegroup Admin " +
         " -samplegroup Background " +
         " -samplegroup Connectivity " +
@@ -1389,11 +1423,14 @@
 droiddoc {
     name: "ds-static-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-stubs",
+    ],
     hdf: [
         "android.whichdoc online",
     ],
     proofread_file: "ds-static-docs-proofrerad.txt",
-    args: framework_docs_args +
+    args: framework_docs_only_args +
           " -staticonly " +
           " -toroot / " +
           " -devsite " +
@@ -1403,11 +1440,14 @@
 droiddoc {
     name: "ds-ref-navtree-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-stubs",
+    ],
     hdf: [
         "android.whichdoc online",
     ],
     proofread_file: "ds-ref-navtree-docs-proofrerad.txt",
-    args: framework_docs_args +
+    args: framework_docs_only_args +
           " -toroot / " +
           " -atLinksNavtree " +
           " -navtreeonly ",
@@ -1416,12 +1456,15 @@
 droiddoc {
     name: "online-sdk-dev-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-stubs",
+    ],
     hdf: [
         "android.whichdoc online",
         "android.hasSamples true",
     ],
     proofread_file: "online-sdk-dev-docs-proofrerad.txt",
-    args: framework_docs_args +
+    args: framework_docs_only_args +
         " -toroot / -samplegroup Admin " +
         " -samplegroup Background " +
         " -samplegroup Connectivity " +
@@ -1442,13 +1485,16 @@
 droiddoc {
     name: "hidden-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-stubs",
+    ],
     proofread_file: "hidden-docs-proofrerad.txt",
-    args: framework_docs_args +
+    args: framework_docs_only_args +
           " -referenceonly " +
           " -title \"Android SDK - Including hidden APIs.\"",
 }
 
-droiddoc {
+droidstubs {
     name: "hwbinder-stubs-docs",
     srcs: [
         "core/java/android/os/HidlSupport.java",
@@ -1466,10 +1512,15 @@
         "core/java/android/os/RemoteException.java",
         "core/java/android/util/AndroidException.java",
     ],
-    custom_template: "droiddoc-templates-sdk",
     installable: false,
     no_framework_libs: true,
-    args: "-showAnnotation android.annotation.SystemApi -nodocs -stubsourceonly",
+    annotations_enabled: true,
+    previous_api: ":last-released-public-api",
+    merge_annotations_dirs: [
+        "metalava-manual",
+        "ojluni-annotated-sdk-stubs",
+    ],
+    args: " --show-annotation android.annotation.SystemApi",
 }
 
 java_library_static {
@@ -1496,23 +1547,17 @@
 }
 
 
-droiddoc {
+droidstubs {
     name: "hiddenapi-mappings",
-    defaults: ["api-stubs-default"],
+    defaults: ["metalava-api-stubs-default"],
     arg_files: [
         "core/res/AndroidManifest.xml",
-        ":api-version-xml",
-        "core/java/overview.html",
-        ":current-support-api",
-        "api/current.txt",
     ],
     dex_mapping_filename: "dex-mapping.txt",
-    args: framework_docs_args +
-          " -referenceonly" +
-          " -nodocs" +
-          " -showUnannotated" +
-          " -showAnnotation android.annotation.SystemApi" +
-          " -showAnnotation android.annotation.TestApi",
+    args: metalava_framework_docs_args +
+        " --show-unannotated " +
+        " --show-annotation android.annotation.SystemApi " +
+        " --show-annotation android.annotation.TestApi "
 }
 
 filegroup {
@@ -1559,6 +1604,7 @@
             removed_api_file: "api/removed.txt",
         },
     },
+    jdiff_enabled: true,
 }
 
 droidstubs {
@@ -1583,6 +1629,7 @@
             removed_api_file: "api/system-removed.txt",
         },
     },
+    jdiff_enabled: true,
 }
 
 droidstubs {
diff --git a/Android.mk b/Android.mk
index 5c4c237..d333074 100644
--- a/Android.mk
+++ b/Android.mk
@@ -53,265 +53,16 @@
 	cat $^ | sort -u > $@.tmp
 	$(call commit-change-for-toc,$@)
 
-# the documentation
-# ============================================================
-
-# TODO: deal with com/google/android/googleapps
-packages_to_document := \
-  android \
-  javax/microedition/khronos \
-  org/apache/http/conn \
-  org/apache/http/params \
-
-# include definition of libcore_to_document
-include libcore/Docs.mk
-
-non_base_dirs := \
-  ../opt/telephony/src/java/android/telephony \
-  ../opt/telephony/src/java/android/telephony/gsm \
-  ../opt/net/voip/src/java/android/net/rtp \
-  ../opt/net/voip/src/java/android/net/sip \
-
-# Find all files in specific directories (relative to frameworks/base)
-# to document and check apis
-files_to_check_apis := \
-  $(call find-other-java-files, \
-    $(non_base_dirs) \
-  )
-
-# Find all files in specific packages that were used to compile
-# framework.jar to document and check apis
-files_to_check_apis += \
-  $(addprefix ../../,\
-    $(filter \
-      $(foreach dir,$(FRAMEWORKS_BASE_JAVA_SRC_DIRS),\
-        $(foreach package,$(packages_to_document),\
-          $(dir)/$(package)/%.java)),\
-      $(SOONG_FRAMEWORK_SRCS)))
-
-# Find all generated files that were used to compile framework.jar
-files_to_check_apis_generated := \
-  $(filter $(OUT_DIR)/%,\
-    $(SOONG_FRAMEWORK_SRCS))
-
-# These are relative to frameworks/base
-# FRAMEWORKS_BASE_SUBDIRS comes from build/core/pathmap.mk
-files_to_document := \
-  $(files_to_check_apis) \
-  $(call find-other-java-files,\
-    test-base/src \
-    test-mock/src \
-    test-runner/src)
-
-# These are relative to frameworks/base
-html_dirs := \
-	$(FRAMEWORKS_BASE_SUBDIRS) \
-	$(non_base_dirs) \
-
-# Common sources for doc check and api check
-common_src_files := \
-	$(call find-other-html-files, $(html_dirs)) \
-	$(addprefix ../../, $(libcore_to_document)) \
-
-# These are relative to frameworks/base
-framework_docs_LOCAL_SRC_FILES := \
-  $(files_to_document) \
-  $(common_src_files) \
-
-# These are relative to frameworks/base
-framework_docs_LOCAL_API_CHECK_SRC_FILES := \
-  $(files_to_check_apis) \
-  $(common_src_files) \
-
 # This is used by ide.mk as the list of source files that are
 # always included.
 INTERNAL_SDK_SOURCE_DIRS := $(addprefix $(LOCAL_PATH)/,$(dirs_to_document))
 
-framework_docs_LOCAL_DROIDDOC_SOURCE_PATH := \
-	$(FRAMEWORKS_BASE_JAVA_SRC_DIRS)
-
-framework_docs_LOCAL_SRCJARS := $(SOONG_FRAMEWORK_SRCJARS)
-
-framework_docs_LOCAL_GENERATED_SOURCES := \
-  $(libcore_to_document_generated) \
-  $(files_to_check_apis_generated) \
-
-framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES := \
-	core-oj \
-	core-libart \
-	conscrypt \
-	bouncycastle \
-	okhttp \
-	ext \
-	framework \
-	voip-common \
-
-# Platform docs can refer to Support Library APIs, but we don't actually build
-# them as part of the docs target, so we need to include them on the classpath.
-framework_docs_LOCAL_JAVA_LIBRARIES := \
-	$(framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES) \
-	$(FRAMEWORKS_SUPPORT_JAVA_LIBRARIES)
-
-framework_docs_LOCAL_MODULE_CLASS := JAVA_LIBRARIES
-framework_docs_LOCAL_DROIDDOC_HTML_DIR := docs/html
-# The since flag (-since N.xml API_LEVEL) is used to add API Level information
-# to the reference documentation. Must be in order of oldest to newest.
-#
-# Conscrypt (com.android.org.conscrypt) is an implementation detail and should
-# not be referenced in the documentation.
-framework_docs_LOCAL_DROIDDOC_OPTIONS := \
-    -android \
-    -knowntags ./frameworks/base/docs/knowntags.txt \
-    -knowntags ./libcore/known_oj_tags.txt \
-    -manifest ./frameworks/base/core/res/AndroidManifest.xml \
-    -hidePackage com.android.internal \
-    -hidePackage com.android.internal.util \
-    -hidePackage com.android.okhttp \
-    -hidePackage com.android.org.conscrypt \
-    -hidePackage com.android.server
-
-# Convert an sdk level to a "since" argument.
-since-arg = -since $(wildcard $(HISTORICAL_SDK_VERSIONS_ROOT)/$(1)/public/api/android.$(2)) $(1)
-
-finalized_xml_sdks := $(call numerically_sort,\
-    $(patsubst $(HISTORICAL_SDK_VERSIONS_ROOT)/%/public/api/android.xml,%,\
-    $(wildcard $(HISTORICAL_SDK_VERSIONS_ROOT)/*/public/api/android.xml)))
-finalized_txt_sdks := $(call numerically_sort,\
-     $(patsubst $(HISTORICAL_SDK_VERSIONS_ROOT)/%/public/api/android.txt,%,\
-    $(wildcard $(HISTORICAL_SDK_VERSIONS_ROOT)/*/public/api/android.txt)))
-
-framework_docs_LOCAL_DROIDDOC_OPTIONS += $(foreach sdk,$(finalized_xml_sdks),$(call since-arg,$(sdk),xml))
-framework_docs_LOCAL_DROIDDOC_OPTIONS += $(foreach sdk,$(finalized_txt_sdks),$(call since-arg,$(sdk),txt))
-ifneq ($(PLATFORM_VERSION_CODENAME),REL)
-  framework_docs_LOCAL_DROIDDOC_OPTIONS += \
-      -since ./frameworks/base/api/current.txt $(PLATFORM_VERSION_CODENAME)
-endif
-framework_docs_LOCAL_DROIDDOC_OPTIONS += \
-    -werror -lerror -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 \
-    -overview $(LOCAL_PATH)/core/java/overview.html
-
-framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR:= \
-	$(call intermediates-dir-for,JAVA_LIBRARIES,framework,,COMMON)
-
-framework_docs_LOCAL_ADDITIONAL_JAVA_DIR:= \
-	$(framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR)
-
-framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES := \
-    frameworks/base/docs/knowntags.txt \
-    $(libcore_to_document_generated)
-
-samples_dir := development/samples/browseable
-
-# Whitelist of valid groups, used for default TOC grouping. Each sample must
-# belong to one (and only one) group. Assign samples to groups by setting
-# a sample.group var to one of these groups in the sample's _index.jd.
-sample_groups := -samplegroup Admin \
-                 -samplegroup Background \
-                 -samplegroup Connectivity \
-                 -samplegroup Content \
-                 -samplegroup Input \
-                 -samplegroup Media \
-                 -samplegroup Notification \
-                 -samplegroup RenderScript \
-                 -samplegroup Security \
-                 -samplegroup Sensors \
-                 -samplegroup System \
-                 -samplegroup Testing \
-                 -samplegroup UI \
-                 -samplegroup Views \
-                 -samplegroup Wearable
-
-## SDK version identifiers used in the published docs
-  # major[.minor] version for current SDK. (full releases only)
-framework_docs_SDK_VERSION:=7.0
-  # release version (ie "Release x")  (full releases only)
-framework_docs_SDK_REL_ID:=1
-
-framework_docs_LOCAL_DROIDDOC_OPTIONS += \
-		-hdf dac true \
-		-hdf sdk.codename O \
-		-hdf sdk.preview.version 1 \
-		-hdf sdk.version $(framework_docs_SDK_VERSION) \
-		-hdf sdk.rel.id $(framework_docs_SDK_REL_ID) \
-		-hdf sdk.preview 0 \
-		-resourcesdir $(LOCAL_PATH)/docs/html/reference/images/ \
-		-resourcesoutdir reference/android/images/
-
-# Federate Support Library references against local API file.
-framework_docs_LOCAL_DROIDDOC_OPTIONS += \
-		-federate SupportLib https://developer.android.com \
-		-federationapi SupportLib prebuilts/sdk/current/support-api.txt
-
-# Federate AndroidX references against local API file.
-framework_docs_LOCAL_DROIDDOC_OPTIONS += \
-		-federate AndroidX https://developer.android.com \
-		-federationapi AndroidX prebuilts/sdk/current/androidx-api.txt
-
-# Get the highest numbered api txt for the given api level.
-# $(1): the api level (e.g. public, system)
-define highest_sdk_txt
-$(HISTORICAL_SDK_VERSIONS_ROOT)/$(lastword $(call numerically_sort, \
-    $(patsubst \
-        $(HISTORICAL_SDK_VERSIONS_ROOT)/%,\
-        %,\
-        $(wildcard $(HISTORICAL_SDK_VERSIONS_ROOT)/*/$(1)/api/android.txt)\
-    ) \
-))
-endef
-
-# ====  Public API diff ===========================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(framework_docs_LOCAL_API_CHECK_SRC_FILES)
-LOCAL_GENERATED_SOURCES := $(framework_docs_LOCAL_GENERATED_SOURCES)
-LOCAL_SRCJARS:=$(framework_docs_LOCAL_SRCJARS)
-LOCAL_JAVA_LIBRARIES := $(framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES)
-LOCAL_MODULE_CLASS := $(framework_docs_LOCAL_MODULE_CLASS)
-LOCAL_ADDITIONAL_JAVA_DIR := $(framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR)
-LOCAL_ADDITIONAL_DEPENDENCIES := \
-	$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES) \
-	$(INTERNAL_PLATFORM_API_FILE)
-
-LOCAL_MODULE := offline-sdk-referenceonly
-
-# Basename, because apidiff adds .txt internally.
-LOCAL_APIDIFF_OLDAPI := $(basename $(call highest_sdk_txt,public))
-LOCAL_APIDIFF_NEWAPI := $(LOCAL_PATH)/../../$(basename $(INTERNAL_PLATFORM_API_FILE))
-
-include $(BUILD_APIDIFF)
-
-# Hack to get diffs included in docs output
-out_zip := $(OUT_DOCS)/$(LOCAL_MODULE)-docs.zip
-$(out_zip): $(full_target)
-
-# ====  System API diff ===========================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(framework_docs_LOCAL_API_CHECK_SRC_FILES)
-LOCAL_GENERATED_SOURCES := $(framework_docs_LOCAL_GENERATED_SOURCES)
-LOCAL_SRCJARS:=$(framework_docs_LOCAL_SRCJARS)
-LOCAL_JAVA_LIBRARIES := $(framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES)
-LOCAL_MODULE_CLASS := $(framework_docs_LOCAL_MODULE_CLASS)
-LOCAL_ADDITIONAL_JAVA_DIR := $(framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR)
-LOCAL_ADDITIONAL_DEPENDENCIES := \
-	$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES) \
-	$(INTERNAL_PLATFORM_SYSTEM_API_FILE)
-
-LOCAL_MODULE := offline-system-sdk-referenceonly
-
-# Basename, because apidiff adds .txt internally.
-LOCAL_APIDIFF_OLDAPI := $(basename $(call highest_sdk_txt,system))
-LOCAL_APIDIFF_NEWAPI := $(LOCAL_PATH)/../../$(basename $(INTERNAL_PLATFORM_SYSTEM_API_FILE))
-
-include $(BUILD_APIDIFF)
-
-# Hack to get diffs included in docs output
-out_zip := $(OUT_DOCS)/$(LOCAL_MODULE)-docs.zip
-$(out_zip): $(full_target)
-
 $(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_API_FILE))
 $(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_SYSTEM_API_FILE))
 $(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_TEST_API_FILE))
+$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_API_FILE):apistubs/android/public/api/android.txt)
+$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_SYSTEM_API_FILE):apistubs/android/system/api/android.txt)
+$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_TEST_API_FILE):apistubs/android/test/api/android.txt)
 
 # sdk.atree needs to copy the whole dir: $(OUT_DOCS)/offline-sdk to the final zip.
 # So keep offline-sdk-timestamp target here, and unzip offline-sdk-docs.zip to
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index de83f3e..ff40f75 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -8,6 +8,11 @@
                       services/print/
                       services/usb/
                       telephony/
+                      tests/ActivityViewTest/
+                      tests/LotsOfApps/
+                      tests/NativeProcessesMemoryTest/
+                      tests/OdmApps/
+                      tests/SystemMemoryTest/
                       wifi/
 
 api_lint_hook = ${REPO_ROOT}/frameworks/base/tools/apilint/apilint_sha.sh ${PREUPLOAD_COMMIT}
diff --git a/api/current.txt b/api/current.txt
index 2c2bc5f..da15c07 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -37,6 +37,7 @@
     field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
     field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
     field public static final java.lang.String BIND_SCREENING_SERVICE = "android.permission.BIND_SCREENING_SERVICE";
+    field public static final java.lang.String BIND_SMS_APP_SERVICE = "android.permission.BIND_SMS_APP_SERVICE";
     field public static final java.lang.String BIND_TELECOM_CONNECTION_SERVICE = "android.permission.BIND_TELECOM_CONNECTION_SERVICE";
     field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
     field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
@@ -772,6 +773,7 @@
     field public static final int isFeatureSplit = 16844123; // 0x101055b
     field public static final int isGame = 16843764; // 0x10103f4
     field public static final int isIndicator = 16843079; // 0x1010147
+    field public static final int isLightTheme = 16844175; // 0x101058f
     field public static final int isModifier = 16843334; // 0x1010246
     field public static final int isRepeatable = 16843336; // 0x1010248
     field public static final int isScrollContainer = 16843342; // 0x101024e
@@ -2905,6 +2907,7 @@
     field public static final deprecated int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
     field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
     field public static final int FLAG_REQUEST_FINGERPRINT_GESTURES = 512; // 0x200
+    field public static final int FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK = 1024; // 0x400
     field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
     field public static final int FLAG_RETRIEVE_INTERACTIVE_WINDOWS = 64; // 0x40
     field public int eventTypes;
@@ -4295,6 +4298,20 @@
     method public abstract void onActivityCreated(android.app.Activity, android.os.Bundle);
     method public abstract void onActivityDestroyed(android.app.Activity);
     method public abstract void onActivityPaused(android.app.Activity);
+    method public default void onActivityPostCreated(android.app.Activity, android.os.Bundle);
+    method public default void onActivityPostDestroyed(android.app.Activity);
+    method public default void onActivityPostPaused(android.app.Activity);
+    method public default void onActivityPostResumed(android.app.Activity);
+    method public default void onActivityPostSaveInstanceState(android.app.Activity, android.os.Bundle);
+    method public default void onActivityPostStarted(android.app.Activity);
+    method public default void onActivityPostStopped(android.app.Activity);
+    method public default void onActivityPreCreated(android.app.Activity, android.os.Bundle);
+    method public default void onActivityPreDestroyed(android.app.Activity);
+    method public default void onActivityPrePaused(android.app.Activity);
+    method public default void onActivityPreResumed(android.app.Activity);
+    method public default void onActivityPreSaveInstanceState(android.app.Activity, android.os.Bundle);
+    method public default void onActivityPreStarted(android.app.Activity);
+    method public default void onActivityPreStopped(android.app.Activity);
     method public abstract void onActivityResumed(android.app.Activity);
     method public abstract void onActivitySaveInstanceState(android.app.Activity, android.os.Bundle);
     method public abstract void onActivityStarted(android.app.Activity);
@@ -4385,6 +4402,7 @@
 
   public final class AutomaticZenRule implements android.os.Parcelable {
     ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean);
+    ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, android.service.notification.ZenPolicy, boolean);
     ctor public AutomaticZenRule(android.os.Parcel);
     method public int describeContents();
     method public android.net.Uri getConditionId();
@@ -4392,11 +4410,13 @@
     method public int getInterruptionFilter();
     method public java.lang.String getName();
     method public android.content.ComponentName getOwner();
+    method public android.service.notification.ZenPolicy getZenPolicy();
     method public boolean isEnabled();
     method public void setConditionId(android.net.Uri);
     method public void setEnabled(boolean);
     method public void setInterruptionFilter(int);
     method public void setName(java.lang.String);
+    method public void setZenPolicy(android.service.notification.ZenPolicy);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.AutomaticZenRule> CREATOR;
   }
@@ -5577,14 +5597,14 @@
     ctor public Notification.WearableExtender(android.app.Notification);
     method public android.app.Notification.WearableExtender addAction(android.app.Notification.Action);
     method public android.app.Notification.WearableExtender addActions(java.util.List<android.app.Notification.Action>);
-    method public android.app.Notification.WearableExtender addPage(android.app.Notification);
-    method public android.app.Notification.WearableExtender addPages(java.util.List<android.app.Notification>);
+    method public deprecated android.app.Notification.WearableExtender addPage(android.app.Notification);
+    method public deprecated android.app.Notification.WearableExtender addPages(java.util.List<android.app.Notification>);
     method public android.app.Notification.WearableExtender clearActions();
-    method public android.app.Notification.WearableExtender clearPages();
+    method public deprecated android.app.Notification.WearableExtender clearPages();
     method public android.app.Notification.WearableExtender clone();
     method public android.app.Notification.Builder extend(android.app.Notification.Builder);
     method public java.util.List<android.app.Notification.Action> getActions();
-    method public android.graphics.Bitmap getBackground();
+    method public deprecated android.graphics.Bitmap getBackground();
     method public java.lang.String getBridgeTag();
     method public int getContentAction();
     method public deprecated int getContentIcon();
@@ -5593,17 +5613,17 @@
     method public deprecated int getCustomContentHeight();
     method public deprecated int getCustomSizePreset();
     method public java.lang.String getDismissalId();
-    method public android.app.PendingIntent getDisplayIntent();
+    method public deprecated android.app.PendingIntent getDisplayIntent();
     method public deprecated int getGravity();
-    method public boolean getHintAmbientBigPicture();
+    method public deprecated boolean getHintAmbientBigPicture();
     method public deprecated boolean getHintAvoidBackgroundClipping();
     method public boolean getHintContentIntentLaunchesActivity();
     method public deprecated boolean getHintHideIcon();
     method public deprecated int getHintScreenTimeout();
     method public deprecated boolean getHintShowBackgroundOnly();
-    method public java.util.List<android.app.Notification> getPages();
+    method public deprecated java.util.List<android.app.Notification> getPages();
     method public boolean getStartScrollBottom();
-    method public android.app.Notification.WearableExtender setBackground(android.graphics.Bitmap);
+    method public deprecated android.app.Notification.WearableExtender setBackground(android.graphics.Bitmap);
     method public android.app.Notification.WearableExtender setBridgeTag(java.lang.String);
     method public android.app.Notification.WearableExtender setContentAction(int);
     method public deprecated android.app.Notification.WearableExtender setContentIcon(int);
@@ -5612,23 +5632,23 @@
     method public deprecated android.app.Notification.WearableExtender setCustomContentHeight(int);
     method public deprecated android.app.Notification.WearableExtender setCustomSizePreset(int);
     method public android.app.Notification.WearableExtender setDismissalId(java.lang.String);
-    method public android.app.Notification.WearableExtender setDisplayIntent(android.app.PendingIntent);
+    method public deprecated android.app.Notification.WearableExtender setDisplayIntent(android.app.PendingIntent);
     method public deprecated android.app.Notification.WearableExtender setGravity(int);
-    method public android.app.Notification.WearableExtender setHintAmbientBigPicture(boolean);
+    method public deprecated android.app.Notification.WearableExtender setHintAmbientBigPicture(boolean);
     method public deprecated android.app.Notification.WearableExtender setHintAvoidBackgroundClipping(boolean);
     method public android.app.Notification.WearableExtender setHintContentIntentLaunchesActivity(boolean);
     method public deprecated android.app.Notification.WearableExtender setHintHideIcon(boolean);
     method public deprecated android.app.Notification.WearableExtender setHintScreenTimeout(int);
     method public deprecated android.app.Notification.WearableExtender setHintShowBackgroundOnly(boolean);
     method public android.app.Notification.WearableExtender setStartScrollBottom(boolean);
-    field public static final int SCREEN_TIMEOUT_LONG = -1; // 0xffffffff
-    field public static final int SCREEN_TIMEOUT_SHORT = 0; // 0x0
-    field public static final int SIZE_DEFAULT = 0; // 0x0
-    field public static final int SIZE_FULL_SCREEN = 5; // 0x5
-    field public static final int SIZE_LARGE = 4; // 0x4
-    field public static final int SIZE_MEDIUM = 3; // 0x3
-    field public static final int SIZE_SMALL = 2; // 0x2
-    field public static final int SIZE_XSMALL = 1; // 0x1
+    field public static final deprecated int SCREEN_TIMEOUT_LONG = -1; // 0xffffffff
+    field public static final deprecated int SCREEN_TIMEOUT_SHORT = 0; // 0x0
+    field public static final deprecated int SIZE_DEFAULT = 0; // 0x0
+    field public static final deprecated int SIZE_FULL_SCREEN = 5; // 0x5
+    field public static final deprecated int SIZE_LARGE = 4; // 0x4
+    field public static final deprecated int SIZE_MEDIUM = 3; // 0x3
+    field public static final deprecated int SIZE_SMALL = 2; // 0x2
+    field public static final deprecated int SIZE_XSMALL = 1; // 0x1
     field public static final int UNSET_ACTION_INDEX = -1; // 0xffffffff
   }
 
@@ -6091,6 +6111,11 @@
     method public abstract void onSharedElementsReady();
   }
 
+  public class SmsAppService extends android.app.Service {
+    ctor public SmsAppService();
+    method public final android.os.IBinder onBind(android.content.Intent);
+  }
+
   public deprecated class TabActivity extends android.app.ActivityGroup {
     ctor public TabActivity();
     method public android.widget.TabHost getTabHost();
@@ -7730,7 +7755,9 @@
     method public boolean isMultipleAdvertisementSupported();
     method public boolean isOffloadedFilteringSupported();
     method public boolean isOffloadedScanBatchingSupported();
+    method public android.bluetooth.BluetoothServerSocket listenUsingInsecureL2capChannel() throws java.io.IOException;
     method public android.bluetooth.BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(java.lang.String, java.util.UUID) throws java.io.IOException;
+    method public android.bluetooth.BluetoothServerSocket listenUsingL2capChannel() throws java.io.IOException;
     method public android.bluetooth.BluetoothServerSocket listenUsingRfcommWithServiceRecord(java.lang.String, java.util.UUID) throws java.io.IOException;
     method public boolean setName(java.lang.String);
     method public boolean startDiscovery();
@@ -8098,7 +8125,9 @@
     method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int);
     method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int, android.os.Handler);
     method public boolean createBond();
+    method public android.bluetooth.BluetoothSocket createInsecureL2capChannel(int) throws java.io.IOException;
     method public android.bluetooth.BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
+    method public android.bluetooth.BluetoothSocket createL2capChannel(int) throws java.io.IOException;
     method public android.bluetooth.BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
     method public int describeContents();
     method public boolean fetchUuidsWithSdp();
@@ -8514,6 +8543,7 @@
     method public android.bluetooth.BluetoothSocket accept() throws java.io.IOException;
     method public android.bluetooth.BluetoothSocket accept(int) throws java.io.IOException;
     method public void close() throws java.io.IOException;
+    method public int getPsm();
   }
 
   public final class BluetoothSocket implements java.io.Closeable {
@@ -9340,6 +9370,7 @@
     ctor public ContentUris();
     method public static android.net.Uri.Builder appendId(android.net.Uri.Builder, long);
     method public static long parseId(android.net.Uri);
+    method public static android.net.Uri removeId(android.net.Uri);
     method public static android.net.Uri withAppendedId(android.net.Uri, long);
   }
 
@@ -9517,6 +9548,7 @@
     field public static final int BIND_IMPORTANT = 64; // 0x40
     field public static final int BIND_NOT_FOREGROUND = 4; // 0x4
     field public static final int BIND_WAIVE_PRIORITY = 32; // 0x20
+    field public static final java.lang.String BIOMETRIC_SERVICE = "biometric";
     field public static final java.lang.String BLUETOOTH_SERVICE = "bluetooth";
     field public static final java.lang.String CAMERA_SERVICE = "camera";
     field public static final java.lang.String CAPTIONING_SERVICE = "captioning";
@@ -11928,6 +11960,7 @@
     method public android.graphics.drawable.Drawable getDrawable(int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
     method public deprecated android.graphics.drawable.Drawable getDrawableForDensity(int, int) throws android.content.res.Resources.NotFoundException;
     method public android.graphics.drawable.Drawable getDrawableForDensity(int, int, android.content.res.Resources.Theme);
+    method public float getFloat(int);
     method public android.graphics.Typeface getFont(int) throws android.content.res.Resources.NotFoundException;
     method public float getFraction(int, int, int);
     method public int getIdentifier(java.lang.String, java.lang.String, java.lang.String);
@@ -12655,7 +12688,7 @@
     ctor public SQLiteMisuseException(java.lang.String);
   }
 
-  public abstract class SQLiteOpenHelper {
+  public abstract class SQLiteOpenHelper implements java.lang.AutoCloseable {
     ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int);
     ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int, android.database.DatabaseErrorHandler);
     ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, int, android.database.sqlite.SQLiteDatabase.OpenParams);
@@ -13995,6 +14028,10 @@
     method public float getRunAdvance(char[], int, int, int, int, boolean, int);
     method public float getRunAdvance(java.lang.CharSequence, int, int, int, int, boolean, int);
     method public android.graphics.Shader getShader();
+    method public int getShadowLayerColor();
+    method public float getShadowLayerDx();
+    method public float getShadowLayerDy();
+    method public float getShadowLayerRadius();
     method public float getStrikeThruPosition();
     method public float getStrikeThruThickness();
     method public android.graphics.Paint.Cap getStrokeCap();
@@ -14004,11 +14041,15 @@
     method public android.graphics.Paint.Style getStyle();
     method public android.graphics.Paint.Align getTextAlign();
     method public void getTextBounds(java.lang.String, int, int, android.graphics.Rect);
+    method public void getTextBounds(java.lang.CharSequence, int, int, android.graphics.Rect);
     method public void getTextBounds(char[], int, int, android.graphics.Rect);
     method public java.util.Locale getTextLocale();
     method public android.os.LocaleList getTextLocales();
     method public void getTextPath(char[], int, int, float, float, android.graphics.Path);
     method public void getTextPath(java.lang.String, int, int, float, float, android.graphics.Path);
+    method public float getTextRunAdvances(char[], int, int, int, int, boolean, float[], int);
+    method public int getTextRunCursor(char[], int, int, boolean, int, int);
+    method public int getTextRunCursor(java.lang.CharSequence, int, int, boolean, int, int);
     method public float getTextScaleX();
     method public float getTextSize();
     method public float getTextSkewX();
@@ -14075,6 +14116,11 @@
     method public void setWordSpacing(float);
     method public android.graphics.Xfermode setXfermode(android.graphics.Xfermode);
     field public static final int ANTI_ALIAS_FLAG = 1; // 0x1
+    field public static final int CURSOR_AFTER = 0; // 0x0
+    field public static final int CURSOR_AT = 4; // 0x4
+    field public static final int CURSOR_AT_OR_AFTER = 1; // 0x1
+    field public static final int CURSOR_AT_OR_BEFORE = 3; // 0x3
+    field public static final int CURSOR_BEFORE = 2; // 0x2
     field public static final int DEV_KERN_TEXT_FLAG = 256; // 0x100
     field public static final int DITHER_FLAG = 4; // 0x4
     field public static final int EMBEDDED_BITMAP_TEXT_FLAG = 1024; // 0x400
@@ -15289,7 +15335,7 @@
     method public static java.lang.String toFontVariationSettings(android.graphics.fonts.FontVariationAxis[]);
   }
 
-  public class SystemFonts {
+  public final class SystemFonts {
     method public static java.util.Set<android.graphics.fonts.Font> getAvailableFonts();
   }
 
@@ -15914,6 +15960,10 @@
 
 package android.hardware.biometrics {
 
+  public class BiometricManager {
+    method public boolean hasEnrolledBiometrics();
+  }
+
   public class BiometricPrompt {
     method public void authenticate(android.hardware.biometrics.BiometricPrompt.CryptoObject, android.os.CancellationSignal, java.util.concurrent.Executor, android.hardware.biometrics.BiometricPrompt.AuthenticationCallback);
     method public void authenticate(android.os.CancellationSignal, java.util.concurrent.Executor, android.hardware.biometrics.BiometricPrompt.AuthenticationCallback);
@@ -16033,6 +16083,7 @@
     method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailablePhysicalCameraRequestKeys();
     method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailableSessionKeys();
     method public java.util.List<android.hardware.camera2.CameraCharacteristics.Key<?>> getKeys();
+    method public java.util.List<android.hardware.camera2.CameraCharacteristics.Key<?>> getKeysNeedingPermission();
     method public java.util.Set<java.lang.String> getPhysicalCameraIds();
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AE_AVAILABLE_ANTIBANDING_MODES;
@@ -18618,6 +18669,114 @@
     method public java.lang.CharSequence getName();
   }
 
+  public class Bidi {
+    ctor public Bidi();
+    ctor public Bidi(int, int);
+    ctor public Bidi(java.lang.String, int);
+    ctor public Bidi(java.text.AttributedCharacterIterator);
+    ctor public Bidi(char[], int, byte[], int, int, int);
+    method public boolean baseIsLeftToRight();
+    method public int countParagraphs();
+    method public int countRuns();
+    method public android.icu.text.Bidi createLineBidi(int, int);
+    method public static byte getBaseDirection(java.lang.CharSequence);
+    method public int getBaseLevel();
+    method public android.icu.text.BidiClassifier getCustomClassifier();
+    method public int getCustomizedClass(int);
+    method public byte getDirection();
+    method public int getLength();
+    method public byte getLevelAt(int);
+    method public byte[] getLevels();
+    method public int getLogicalIndex(int);
+    method public int[] getLogicalMap();
+    method public android.icu.text.BidiRun getLogicalRun(int);
+    method public byte getParaLevel();
+    method public android.icu.text.BidiRun getParagraph(int);
+    method public android.icu.text.BidiRun getParagraphByIndex(int);
+    method public int getParagraphIndex(int);
+    method public int getProcessedLength();
+    method public int getReorderingMode();
+    method public int getReorderingOptions();
+    method public int getResultLength();
+    method public int getRunCount();
+    method public int getRunLevel(int);
+    method public int getRunLimit(int);
+    method public int getRunStart(int);
+    method public char[] getText();
+    method public java.lang.String getTextAsString();
+    method public int getVisualIndex(int);
+    method public int[] getVisualMap();
+    method public android.icu.text.BidiRun getVisualRun(int);
+    method public static int[] invertMap(int[]);
+    method public boolean isInverse();
+    method public boolean isLeftToRight();
+    method public boolean isMixed();
+    method public boolean isOrderParagraphsLTR();
+    method public boolean isRightToLeft();
+    method public void orderParagraphsLTR(boolean);
+    method public static int[] reorderLogical(byte[]);
+    method public static int[] reorderVisual(byte[]);
+    method public static void reorderVisually(byte[], int, java.lang.Object[], int, int);
+    method public static boolean requiresBidi(char[], int, int);
+    method public void setContext(java.lang.String, java.lang.String);
+    method public void setCustomClassifier(android.icu.text.BidiClassifier);
+    method public void setInverse(boolean);
+    method public android.icu.text.Bidi setLine(int, int);
+    method public void setPara(java.lang.String, byte, byte[]);
+    method public void setPara(char[], byte, byte[]);
+    method public void setPara(java.text.AttributedCharacterIterator);
+    method public void setReorderingMode(int);
+    method public void setReorderingOptions(int);
+    method public java.lang.String writeReordered(int);
+    method public static java.lang.String writeReverse(java.lang.String, int);
+    field public static final int DIRECTION_DEFAULT_LEFT_TO_RIGHT = 126; // 0x7e
+    field public static final int DIRECTION_DEFAULT_RIGHT_TO_LEFT = 127; // 0x7f
+    field public static final int DIRECTION_LEFT_TO_RIGHT = 0; // 0x0
+    field public static final int DIRECTION_RIGHT_TO_LEFT = 1; // 0x1
+    field public static final short DO_MIRRORING = 2; // 0x2
+    field public static final short INSERT_LRM_FOR_NUMERIC = 4; // 0x4
+    field public static final short KEEP_BASE_COMBINING = 1; // 0x1
+    field public static final byte LEVEL_DEFAULT_LTR = 126; // 0x7e
+    field public static final byte LEVEL_DEFAULT_RTL = 127; // 0x7f
+    field public static final byte LEVEL_OVERRIDE = -128; // 0xffffff80
+    field public static final byte LTR = 0; // 0x0
+    field public static final int MAP_NOWHERE = -1; // 0xffffffff
+    field public static final byte MAX_EXPLICIT_LEVEL = 125; // 0x7d
+    field public static final byte MIXED = 2; // 0x2
+    field public static final byte NEUTRAL = 3; // 0x3
+    field public static final int OPTION_DEFAULT = 0; // 0x0
+    field public static final int OPTION_INSERT_MARKS = 1; // 0x1
+    field public static final int OPTION_REMOVE_CONTROLS = 2; // 0x2
+    field public static final int OPTION_STREAMING = 4; // 0x4
+    field public static final short OUTPUT_REVERSE = 16; // 0x10
+    field public static final short REMOVE_BIDI_CONTROLS = 8; // 0x8
+    field public static final short REORDER_DEFAULT = 0; // 0x0
+    field public static final short REORDER_GROUP_NUMBERS_WITH_R = 2; // 0x2
+    field public static final short REORDER_INVERSE_FOR_NUMBERS_SPECIAL = 6; // 0x6
+    field public static final short REORDER_INVERSE_LIKE_DIRECT = 5; // 0x5
+    field public static final short REORDER_INVERSE_NUMBERS_AS_L = 4; // 0x4
+    field public static final short REORDER_NUMBERS_SPECIAL = 1; // 0x1
+    field public static final short REORDER_RUNS_ONLY = 3; // 0x3
+    field public static final byte RTL = 1; // 0x1
+  }
+
+  public class BidiClassifier {
+    ctor public BidiClassifier(java.lang.Object);
+    method public int classify(int);
+    method public java.lang.Object getContext();
+    method public void setContext(java.lang.Object);
+  }
+
+  public class BidiRun {
+    method public byte getDirection();
+    method public byte getEmbeddingLevel();
+    method public int getLength();
+    method public int getLimit();
+    method public int getStart();
+    method public boolean isEvenRun();
+    method public boolean isOddRun();
+  }
+
   public abstract class BreakIterator implements java.lang.Cloneable {
     ctor protected BreakIterator();
     method public java.lang.Object clone();
@@ -18669,6 +18828,37 @@
     field public static final int WORD_NUMBER_LIMIT = 200; // 0xc8
   }
 
+  public abstract class CaseMap {
+    method public static android.icu.text.CaseMap.Fold fold();
+    method public abstract android.icu.text.CaseMap omitUnchangedText();
+    method public static android.icu.text.CaseMap.Lower toLower();
+    method public static android.icu.text.CaseMap.Title toTitle();
+    method public static android.icu.text.CaseMap.Upper toUpper();
+  }
+
+  public static final class CaseMap.Fold extends android.icu.text.CaseMap {
+    method public <A extends java.lang.Appendable> A apply(java.lang.CharSequence, A, android.icu.text.Edits);
+    method public android.icu.text.CaseMap.Fold omitUnchangedText();
+    method public android.icu.text.CaseMap.Fold turkic();
+  }
+
+  public static final class CaseMap.Lower extends android.icu.text.CaseMap {
+    method public <A extends java.lang.Appendable> A apply(java.util.Locale, java.lang.CharSequence, A, android.icu.text.Edits);
+    method public android.icu.text.CaseMap.Lower omitUnchangedText();
+  }
+
+  public static final class CaseMap.Title extends android.icu.text.CaseMap {
+    method public <A extends java.lang.Appendable> A apply(java.util.Locale, android.icu.text.BreakIterator, java.lang.CharSequence, A, android.icu.text.Edits);
+    method public android.icu.text.CaseMap.Title noBreakAdjustment();
+    method public android.icu.text.CaseMap.Title noLowercase();
+    method public android.icu.text.CaseMap.Title omitUnchangedText();
+  }
+
+  public static final class CaseMap.Upper extends android.icu.text.CaseMap {
+    method public <A extends java.lang.Appendable> A apply(java.util.Locale, java.lang.CharSequence, A, android.icu.text.Edits);
+    method public android.icu.text.CaseMap.Upper omitUnchangedText();
+  }
+
   public final class CollationElementIterator {
     method public int getMaxExpansion(int);
     method public int getOffset();
@@ -19334,6 +19524,30 @@
     enum_constant public static final android.icu.text.DisplayContext.Type SUBSTITUTE_HANDLING;
   }
 
+  public final class Edits {
+    ctor public Edits();
+    method public void addReplace(int, int);
+    method public void addUnchanged(int);
+    method public android.icu.text.Edits.Iterator getCoarseChangesIterator();
+    method public android.icu.text.Edits.Iterator getCoarseIterator();
+    method public android.icu.text.Edits.Iterator getFineChangesIterator();
+    method public android.icu.text.Edits.Iterator getFineIterator();
+    method public boolean hasChanges();
+    method public int lengthDelta();
+    method public void reset();
+  }
+
+  public static final class Edits.Iterator {
+    method public int destinationIndex();
+    method public boolean findSourceIndex(int);
+    method public boolean hasChange();
+    method public int newLength();
+    method public boolean next();
+    method public int oldLength();
+    method public int replacementIndex();
+    method public int sourceIndex();
+  }
+
   public abstract class IDNA {
     method public static android.icu.text.IDNA getUTS46Instance(int);
     method public abstract java.lang.StringBuilder labelToASCII(java.lang.CharSequence, java.lang.StringBuilder, android.icu.text.IDNA.Info);
@@ -27069,6 +27283,7 @@
     method public android.net.Network[] getAllNetworks();
     method public deprecated boolean getBackgroundDataSetting();
     method public android.net.Network getBoundNetworkForProcess();
+    method public int getConnectionOwnerUid(int, java.net.InetSocketAddress, java.net.InetSocketAddress);
     method public android.net.ProxyInfo getDefaultProxy();
     method public android.net.LinkProperties getLinkProperties(android.net.Network);
     method public int getMultipathPreference(android.net.Network);
@@ -33216,6 +33431,7 @@
     method public static final void setThreadPriority(int) throws java.lang.IllegalArgumentException, java.lang.SecurityException;
     method public static final deprecated boolean supportsProcesses();
     field public static final int FIRST_APPLICATION_UID = 10000; // 0x2710
+    field public static final int INVALID_UID = -1; // 0xffffffff
     field public static final int LAST_APPLICATION_UID = 19999; // 0x4e1f
     field public static final int PHONE_UID = 1001; // 0x3e9
     field public static final int SIGNAL_KILL = 9; // 0x9
@@ -36588,9 +36804,9 @@
     field public static final java.lang.String IS_PRIVATE = "isprivate";
     field public static final java.lang.String LATITUDE = "latitude";
     field public static final java.lang.String LONGITUDE = "longitude";
-    field public static final java.lang.String MINI_THUMB_MAGIC = "mini_thumb_magic";
+    field public static final deprecated java.lang.String MINI_THUMB_MAGIC = "mini_thumb_magic";
     field public static final java.lang.String ORIENTATION = "orientation";
-    field public static final java.lang.String PICASA_ID = "picasa_id";
+    field public static final deprecated java.lang.String PICASA_ID = "picasa_id";
   }
 
   public static final class MediaStore.Images.Media implements android.provider.MediaStore.Images.ImageColumns {
@@ -36693,7 +36909,7 @@
     field public static final java.lang.String LANGUAGE = "language";
     field public static final java.lang.String LATITUDE = "latitude";
     field public static final java.lang.String LONGITUDE = "longitude";
-    field public static final java.lang.String MINI_THUMB_MAGIC = "mini_thumb_magic";
+    field public static final deprecated java.lang.String MINI_THUMB_MAGIC = "mini_thumb_magic";
     field public static final java.lang.String RESOLUTION = "resolution";
     field public static final java.lang.String TAGS = "tags";
   }
@@ -39565,6 +39781,7 @@
     method public final deprecated void cancelNotification(java.lang.String, java.lang.String, int);
     method public final void cancelNotification(java.lang.String);
     method public final void cancelNotifications(java.lang.String[]);
+    method public final void clearRequestedListenerHints();
     method public android.service.notification.StatusBarNotification[] getActiveNotifications();
     method public android.service.notification.StatusBarNotification[] getActiveNotifications(java.lang.String[]);
     method public final int getCurrentInterruptionFilter();
@@ -39680,6 +39897,61 @@
     field public static final android.os.Parcelable.Creator<android.service.notification.StatusBarNotification> CREATOR;
   }
 
+  public final class ZenPolicy implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getPriorityCallSenders();
+    method public int getPriorityCategoryAlarms();
+    method public int getPriorityCategoryCalls();
+    method public int getPriorityCategoryEvents();
+    method public int getPriorityCategoryMedia();
+    method public int getPriorityCategoryMessages();
+    method public int getPriorityCategoryReminders();
+    method public int getPriorityCategoryRepeatCallers();
+    method public int getPriorityCategorySystem();
+    method public int getPriorityMessageSenders();
+    method public int getVisualEffectAmbient();
+    method public int getVisualEffectBadge();
+    method public int getVisualEffectFullScreenIntent();
+    method public int getVisualEffectLights();
+    method public int getVisualEffectNotificationList();
+    method public int getVisualEffectPeek();
+    method public int getVisualEffectStatusBar();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.notification.ZenPolicy> CREATOR;
+    field public static final int PEOPLE_TYPE_ANYONE = 1; // 0x1
+    field public static final int PEOPLE_TYPE_CONTACTS = 2; // 0x2
+    field public static final int PEOPLE_TYPE_NONE = 4; // 0x4
+    field public static final int PEOPLE_TYPE_STARRED = 3; // 0x3
+    field public static final int PEOPLE_TYPE_UNSET = 0; // 0x0
+    field public static final int STATE_ALLOW = 1; // 0x1
+    field public static final int STATE_DISALLOW = 2; // 0x2
+    field public static final int STATE_UNSET = 0; // 0x0
+  }
+
+  public static class ZenPolicy.Builder {
+    ctor public ZenPolicy.Builder();
+    method public android.service.notification.ZenPolicy.Builder allowAlarms(boolean);
+    method public android.service.notification.ZenPolicy.Builder allowAllSounds();
+    method public android.service.notification.ZenPolicy.Builder allowCalls(int);
+    method public android.service.notification.ZenPolicy.Builder allowEvents(boolean);
+    method public android.service.notification.ZenPolicy.Builder allowMedia(boolean);
+    method public android.service.notification.ZenPolicy.Builder allowMessages(int);
+    method public android.service.notification.ZenPolicy.Builder allowReminders(boolean);
+    method public android.service.notification.ZenPolicy.Builder allowRepeatCallers(boolean);
+    method public android.service.notification.ZenPolicy.Builder allowSystem(boolean);
+    method public android.service.notification.ZenPolicy build();
+    method public android.service.notification.ZenPolicy.Builder disallowAllSounds();
+    method public android.service.notification.ZenPolicy.Builder hideAllVisualEffects();
+    method public android.service.notification.ZenPolicy.Builder showAllVisualEffects();
+    method public android.service.notification.ZenPolicy.Builder showBadges(boolean);
+    method public android.service.notification.ZenPolicy.Builder showFullScreenIntent(boolean);
+    method public android.service.notification.ZenPolicy.Builder showInAmbientDisplay(boolean);
+    method public android.service.notification.ZenPolicy.Builder showInNotificationList(boolean);
+    method public android.service.notification.ZenPolicy.Builder showLights(boolean);
+    method public android.service.notification.ZenPolicy.Builder showPeeking(boolean);
+    method public android.service.notification.ZenPolicy.Builder showStatusBarIcons(boolean);
+  }
+
 }
 
 package android.service.quicksettings {
@@ -39796,6 +40068,7 @@
     method public int getDisabledShowContext();
     method public static boolean isActiveService(android.content.Context, android.content.ComponentName);
     method public android.os.IBinder onBind(android.content.Intent);
+    method public java.util.Set<java.lang.String> onGetSupportedVoiceActions(java.util.Set<java.lang.String>);
     method public void onLaunchVoiceAssistFromKeyguard();
     method public void onReady();
     method public void onShutdown();
@@ -39858,6 +40131,7 @@
     field public static final int SHOW_SOURCE_ACTIVITY = 16; // 0x10
     field public static final int SHOW_SOURCE_APPLICATION = 8; // 0x8
     field public static final int SHOW_SOURCE_ASSIST_GESTURE = 4; // 0x4
+    field public static final int SHOW_SOURCE_NOTIFICATION = 64; // 0x40
     field public static final int SHOW_SOURCE_PUSH_TO_TALK = 32; // 0x20
     field public static final int SHOW_WITH_ASSIST = 1; // 0x1
     field public static final int SHOW_WITH_SCREENSHOT = 2; // 0x2
@@ -41063,6 +41337,7 @@
     field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 128; // 0x80
     field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
     field public static final int PROPERTY_IS_EXTERNAL_CALL = 64; // 0x40
+    field public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 2048; // 0x800
     field public static final int PROPERTY_RTT = 1024; // 0x400
     field public static final int PROPERTY_SELF_MANAGED = 256; // 0x100
     field public static final int PROPERTY_WIFI = 8; // 0x8
@@ -41718,6 +41993,7 @@
     field public static final java.lang.String EXTRA_CALL_BACK_NUMBER = "android.telecom.extra.CALL_BACK_NUMBER";
     field public static final java.lang.String EXTRA_CALL_DISCONNECT_CAUSE = "android.telecom.extra.CALL_DISCONNECT_CAUSE";
     field public static final java.lang.String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecom.extra.CALL_DISCONNECT_MESSAGE";
+    field public static final java.lang.String EXTRA_CALL_NETWORK_TYPE = "android.telecom.extra.CALL_NETWORK_TYPE";
     field public static final java.lang.String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
     field public static final java.lang.String EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME = "android.telecom.extra.CHANGE_DEFAULT_DIALER_PACKAGE_NAME";
     field public static final java.lang.String EXTRA_INCOMING_CALL_ADDRESS = "android.telecom.extra.INCOMING_CALL_ADDRESS";
@@ -42015,6 +42291,7 @@
     field public static final deprecated java.lang.String KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL = "restart_radio_on_pdp_fail_regular_deactivation_bool";
     field public static final java.lang.String KEY_RTT_SUPPORTED_BOOL = "rtt_supported_bool";
     field public static final java.lang.String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool";
+    field public static final java.lang.String KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL = "show_call_blocking_disabled_notification_always_bool";
     field public static final java.lang.String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool";
     field public static final java.lang.String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool";
     field public static final java.lang.String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool";
@@ -42276,6 +42553,13 @@
     field public static final int STATUS_UNKNOWN = 0; // 0x0
   }
 
+  public class MbmsGroupCallSession implements java.lang.AutoCloseable {
+    method public void close();
+    method public static android.telephony.MbmsGroupCallSession create(android.content.Context, java.util.concurrent.Executor, int, android.telephony.mbms.MbmsGroupCallSessionCallback);
+    method public static android.telephony.MbmsGroupCallSession create(android.content.Context, java.util.concurrent.Executor, android.telephony.mbms.MbmsGroupCallSessionCallback);
+    method public android.telephony.mbms.GroupCall startGroupCall(java.util.concurrent.Executor, long, int[], int[], android.telephony.mbms.GroupCallCallback);
+  }
+
   public class MbmsStreamingSession implements java.lang.AutoCloseable {
     method public void close();
     method public static android.telephony.MbmsStreamingSession create(android.content.Context, java.util.concurrent.Executor, int, android.telephony.mbms.MbmsStreamingSessionCallback);
@@ -42654,8 +42938,10 @@
     method public static int getDefaultSubscriptionId();
     method public static int getDefaultVoiceSubscriptionId();
     method public java.util.List<android.telephony.SubscriptionInfo> getOpportunisticSubscriptions(int);
+    method public static int getSlotIndex(int);
     method public static int[] getSubscriptionIds(int);
     method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int);
+    method public boolean isActiveSubscriptionId(int);
     method public boolean isNetworkRoaming(int);
     method public static boolean isValidSubscriptionId(int);
     method public void removeOnOpportunisticSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener);
@@ -42671,7 +42957,9 @@
     field public static final int DATA_ROAMING_DISABLE = 0; // 0x0
     field public static final int DATA_ROAMING_ENABLE = 1; // 0x1
     field public static final java.lang.String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX";
+    field public static final int INVALID_SIM_SLOT_INDEX = -2; // 0xfffffffe
     field public static final int INVALID_SUBSCRIPTION_ID = -1; // 0xffffffff
+    field public static final int SIM_NOT_INSERTED = -3; // 0xfffffffd
   }
 
   public static class SubscriptionManager.OnOpportunisticSubscriptionsChangedListener {
@@ -42806,6 +43094,7 @@
     field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
     field public static final java.lang.String ACTION_SECRET_CODE = "android.telephony.action.SECRET_CODE";
     field public static final java.lang.String ACTION_SHOW_VOICEMAIL_NOTIFICATION = "android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION";
+    field public static final java.lang.String ACTION_SMS_APP_SERVICE = "android.telephony.action.SMS_APP_SERVICE";
     field public static final java.lang.String ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED = "android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED";
     field public static final int APPTYPE_CSIM = 4; // 0x4
     field public static final int APPTYPE_ISIM = 5; // 0x5
@@ -43222,6 +43511,29 @@
     field public static final android.os.Parcelable.Creator<android.telephony.mbms.FileServiceInfo> CREATOR;
   }
 
+  public class GroupCall implements java.lang.AutoCloseable {
+    method public void close();
+    method public long getTmgi();
+    method public void updateGroupCall(int[], int[]);
+    field public static final int REASON_BY_USER_REQUEST = 1; // 0x1
+    field public static final int REASON_FREQUENCY_CONFLICT = 3; // 0x3
+    field public static final int REASON_LEFT_MBMS_BROADCAST_AREA = 6; // 0x6
+    field public static final int REASON_NONE = 0; // 0x0
+    field public static final int REASON_NOT_CONNECTED_TO_HOMECARRIER_LTE = 5; // 0x5
+    field public static final int REASON_OUT_OF_MEMORY = 4; // 0x4
+    field public static final int STATE_STALLED = 3; // 0x3
+    field public static final int STATE_STARTED = 2; // 0x2
+    field public static final int STATE_STOPPED = 1; // 0x1
+  }
+
+  public class GroupCallCallback {
+    ctor public GroupCallCallback();
+    method public void onBroadcastSignalStrengthUpdated(int);
+    method public void onError(int, java.lang.String);
+    method public void onGroupCallStateChanged(int, int);
+    field public static final int SIGNAL_STRENGTH_UNAVAILABLE = -1; // 0xffffffff
+  }
+
   public class MbmsDownloadReceiver extends android.content.BroadcastReceiver {
     ctor public MbmsDownloadReceiver();
     method public void onReceive(android.content.Context, android.content.Intent);
@@ -43270,6 +43582,14 @@
     field public static final int ERROR_UNABLE_TO_START_SERVICE = 302; // 0x12e
   }
 
+  public class MbmsGroupCallSessionCallback {
+    ctor public MbmsGroupCallSessionCallback();
+    method public void onAvailableSaisUpdated(java.util.List<java.lang.Integer>, java.util.List<java.util.List<java.lang.Integer>>);
+    method public void onError(int, java.lang.String);
+    method public void onMiddlewareReady();
+    method public void onServiceInterfaceAvailable(java.lang.String, int);
+  }
+
   public class MbmsStreamingSessionCallback {
     ctor public MbmsStreamingSessionCallback();
     method public void onError(int, java.lang.String);
@@ -43904,6 +44224,8 @@
     field public float density;
     field public int[] drawableState;
     field public int linkColor;
+    field public int underlineColor;
+    field public float underlineThickness;
   }
 
   public class TextUtils {
@@ -44718,11 +45040,20 @@
     ctor public TextAppearanceSpan(android.os.Parcel);
     method public int describeContents();
     method public java.lang.String getFamily();
+    method public java.lang.String getFontFeatureSettings();
+    method public java.lang.String getFontVariationSettings();
     method public android.content.res.ColorStateList getLinkTextColor();
+    method public int getShadowColor();
+    method public float getShadowDx();
+    method public float getShadowDy();
+    method public float getShadowRadius();
     method public int getSpanTypeId();
     method public android.content.res.ColorStateList getTextColor();
+    method public int getTextFontWeight();
     method public int getTextSize();
     method public int getTextStyle();
+    method public android.graphics.Typeface getTypeface();
+    method public boolean isElegantTextHeight();
     method public void updateDrawState(android.text.TextPaint);
     method public void updateMeasureState(android.text.TextPaint);
     method public void writeToParcel(android.os.Parcel, int);
@@ -49634,6 +49965,7 @@
     method public boolean isScrollable();
     method public boolean isSelected();
     method public boolean isShowingHintText();
+    method public boolean isTextEntryKey();
     method public boolean isVisibleToUser();
     method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View);
     method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View, int);
@@ -49695,6 +50027,7 @@
     method public void setSource(android.view.View);
     method public void setSource(android.view.View, int);
     method public void setText(java.lang.CharSequence);
+    method public void setTextEntryKey(boolean);
     method public void setTextSelection(int, int);
     method public void setTooltipText(java.lang.CharSequence);
     method public void setTraversalAfter(android.view.View);
@@ -51106,7 +51439,7 @@
   }
 
   public abstract class CookieManager {
-    ctor public CookieManager();
+    ctor public deprecated CookieManager();
     method public abstract boolean acceptCookie();
     method public abstract boolean acceptThirdPartyCookies(android.webkit.WebView);
     method public static boolean allowFileSchemeCookies();
@@ -51206,13 +51539,13 @@
   }
 
   public abstract class RenderProcessGoneDetail {
-    ctor public RenderProcessGoneDetail();
+    ctor public deprecated RenderProcessGoneDetail();
     method public abstract boolean didCrash();
     method public abstract int rendererPriorityAtExit();
   }
 
   public abstract class SafeBrowsingResponse {
-    ctor public SafeBrowsingResponse();
+    ctor public deprecated SafeBrowsingResponse();
     method public abstract void backToSafety(boolean);
     method public abstract void proceed(boolean);
     method public abstract void showInterstitial(boolean);
@@ -51224,7 +51557,7 @@
   }
 
   public abstract class ServiceWorkerController {
-    ctor public ServiceWorkerController();
+    ctor public deprecated ServiceWorkerController();
     method public static android.webkit.ServiceWorkerController getInstance();
     method public abstract android.webkit.ServiceWorkerWebSettings getServiceWorkerWebSettings();
     method public abstract void setServiceWorkerClient(android.webkit.ServiceWorkerClient);
@@ -51273,7 +51606,7 @@
   }
 
   public abstract class TracingController {
-    ctor public TracingController();
+    ctor public deprecated TracingController();
     method public static android.webkit.TracingController getInstance();
     method public abstract boolean isTracing();
     method public abstract void start(android.webkit.TracingConfig);
@@ -51813,7 +52146,7 @@
   }
 
   public abstract class WebViewDatabase {
-    ctor public WebViewDatabase();
+    ctor public deprecated WebViewDatabase();
     method public abstract deprecated void clearFormData();
     method public abstract void clearHttpAuthUsernamePassword();
     method public abstract deprecated void clearUsernamePassword();
@@ -53093,7 +53426,7 @@
   }
 
   public final class Magnifier {
-    ctor public Magnifier(android.view.View);
+    ctor public deprecated Magnifier(android.view.View);
     method public void dismiss();
     method public float getCornerRadius();
     method public int getDefaultHorizontalSourceToMagnifierOffset();
diff --git a/api/system-current.txt b/api/system-current.txt
index e2c59cb..5785e4a 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -91,6 +91,7 @@
     field public static final java.lang.String KILL_UID = "android.permission.KILL_UID";
     field public static final java.lang.String LOCAL_MAC_ADDRESS = "android.permission.LOCAL_MAC_ADDRESS";
     field public static final java.lang.String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE";
+    field public static final java.lang.String LOCK_DEVICE = "android.permission.LOCK_DEVICE";
     field public static final java.lang.String LOOP_RADIO = "android.permission.LOOP_RADIO";
     field public static final java.lang.String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
     field public static final java.lang.String MANAGE_APP_OPS_RESTRICTIONS = "android.permission.MANAGE_APP_OPS_RESTRICTIONS";
@@ -155,6 +156,7 @@
     field public static final java.lang.String REGISTER_CONNECTION_MANAGER = "android.permission.REGISTER_CONNECTION_MANAGER";
     field public static final java.lang.String REGISTER_SIM_SUBSCRIPTION = "android.permission.REGISTER_SIM_SUBSCRIPTION";
     field public static final java.lang.String REMOVE_DRM_CERTIFICATES = "android.permission.REMOVE_DRM_CERTIFICATES";
+    field public static final java.lang.String RESET_PASSWORD = "android.permission.RESET_PASSWORD";
     field public static final java.lang.String RESTRICTED_VR_ACCESS = "android.permission.RESTRICTED_VR_ACCESS";
     field public static final java.lang.String RETRIEVE_WINDOW_CONTENT = "android.permission.RETRIEVE_WINDOW_CONTENT";
     field public static final java.lang.String REVOKE_RUNTIME_PERMISSIONS = "android.permission.REVOKE_RUNTIME_PERMISSIONS";
@@ -217,6 +219,14 @@
     field public static final int config_sendPackageName = 17891328; // 0x1110000
   }
 
+  public static final class R.dimen {
+    field public static final int config_restricted_icon_size = 17104903; // 0x1050007
+  }
+
+  public static final class R.drawable {
+    field public static final int ic_info = 17301684; // 0x10800b4
+  }
+
   public static final class R.raw {
     field public static final int loaderror = 17825792; // 0x1100000
     field public static final int nodomain = 17825793; // 0x1100001
@@ -940,6 +950,7 @@
     field public static final java.lang.String HDMI_CONTROL_SERVICE = "hdmi_control";
     field public static final java.lang.String NETWORK_SCORE_SERVICE = "network_score";
     field public static final java.lang.String OEM_LOCK_SERVICE = "oem_lock";
+    field public static final java.lang.String PERMISSION_SERVICE = "permission";
     field public static final java.lang.String PERSISTENT_DATA_BLOCK_SERVICE = "persistent_data_block";
     field public static final java.lang.String SECURE_ELEMENT_SERVICE = "secure_element";
     field public static final java.lang.String STATS_MANAGER = "stats";
@@ -1108,6 +1119,7 @@
   public class PackageItemInfo {
     method public deprecated java.lang.CharSequence loadSafeLabel(android.content.pm.PackageManager);
     method public java.lang.CharSequence loadSafeLabel(android.content.pm.PackageManager, float, int);
+    method public static void setForceSafeLabels(boolean);
     field public static final int SAFE_LABEL_FLAG_FIRST_LINE = 4; // 0x4
     field public static final int SAFE_LABEL_FLAG_SINGLE_LINE = 2; // 0x2
     field public static final int SAFE_LABEL_FLAG_TRIM = 1; // 0x1
@@ -3807,6 +3819,14 @@
     field public static final java.lang.String ACTION_UPDATE_SMS_SHORT_CODES = "android.intent.action.UPDATE_SMS_SHORT_CODES";
   }
 
+  public class Environment {
+    method public static java.io.File getOdmDirectory();
+    method public static java.io.File getOemDirectory();
+    method public static java.io.File getProductDirectory();
+    method public static java.io.File getProductServicesDirectory();
+    method public static java.io.File getVendorDirectory();
+  }
+
   public class HidlSupport {
     method public static boolean deepEquals(java.lang.Object, java.lang.Object);
     method public static int deepHashCode(java.lang.Object);
@@ -4107,6 +4127,9 @@
     method public boolean isSystem();
     method public static int myUserId();
     method public static android.os.UserHandle of(int);
+    field public static final android.os.UserHandle ALL;
+    field public static final android.os.UserHandle CURRENT;
+    field public static final android.os.UserHandle SYSTEM;
     field public static final int USER_NULL = -10000; // 0xffffd8f0
   }
 
@@ -4170,6 +4193,20 @@
 
 }
 
+package android.permission {
+
+  public final class PermissionManager {
+    method public java.util.List<android.permission.PermissionManager.SplitPermissionInfo> getSplitPermissions();
+  }
+
+  public static final class PermissionManager.SplitPermissionInfo {
+    method public java.lang.String[] getNewPermissions();
+    method public java.lang.String getRootPermission();
+    method public int getTargetSdk();
+  }
+
+}
+
 package android.permissionpresenterservice {
 
   public abstract class RuntimePermissionPresenterService extends android.app.Service {
@@ -4177,6 +4214,7 @@
     method public final void attachBaseContext(android.content.Context);
     method public final android.os.IBinder onBind(android.content.Intent);
     method public abstract java.util.List<android.content.pm.permission.RuntimePermissionPresentationInfo> onGetAppPermissions(java.lang.String);
+    method public abstract void onRevokeRuntimePermission(java.lang.String, java.lang.String);
     field public static final java.lang.String SERVICE_INTERFACE = "android.permissionpresenterservice.RuntimePermissionPresenterService";
   }
 
@@ -4282,6 +4320,13 @@
     field public static final java.lang.String STATE = "state";
   }
 
+  public static final class ContactsContract.RawContacts implements android.provider.BaseColumns android.provider.ContactsContract.ContactNameColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.RawContactsColumns android.provider.ContactsContract.SyncColumns {
+    field public static final android.net.Uri RAW_CONTACTS_NOTIFICATION_DELETE_URI;
+    field public static final android.net.Uri RAW_CONTACTS_NOTIFICATION_INSERT_URI;
+    field public static final android.net.Uri RAW_CONTACTS_NOTIFICATION_UPDATE_URI;
+    field public static final android.net.Uri RAW_CONTACTS_NOTIFICATION_URI;
+  }
+
   public abstract class SearchIndexableData {
     ctor public SearchIndexableData();
     ctor public SearchIndexableData(android.content.Context);
@@ -5200,6 +5245,7 @@
     method public deprecated android.content.ComponentName getDefaultPhoneApp();
     method public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsForPackage();
     method public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsSupportingScheme(java.lang.String);
+    method public boolean isInEmergencyCall();
     method public boolean isRinging();
     method public boolean isTtySupported();
     field public static final java.lang.String EXTRA_CALL_BACK_INTENT = "android.telecom.extra.CALL_BACK_INTENT";
@@ -5226,6 +5272,10 @@
     field public static final java.lang.String MBMS_DOWNLOAD_SERVICE_ACTION = "android.telephony.action.EmbmsDownload";
   }
 
+  public class MbmsGroupCallSession implements java.lang.AutoCloseable {
+    field public static final java.lang.String MBMS_GROUP_CALL_SERVICE_ACTION = "android.telephony.action.EmbmsGroupCall";
+  }
+
   public class MbmsStreamingSession implements java.lang.AutoCloseable {
     field public static final java.lang.String MBMS_STREAMING_SERVICE_ACTION = "android.telephony.action.EmbmsStreaming";
   }
@@ -5382,7 +5432,6 @@
   }
 
   public class TelephonyManager {
-    method public deprecated void answerRingingCall();
     method public deprecated void call(java.lang.String, java.lang.String);
     method public int checkCarrierPrivilegesForPackage(java.lang.String);
     method public int checkCarrierPrivilegesForPackageAnyPhone(java.lang.String);
@@ -5390,7 +5439,7 @@
     method public boolean disableDataConnectivity();
     method public boolean enableDataConnectivity();
     method public void enableVideoCalling(boolean);
-    method public deprecated boolean endCall();
+    method public java.lang.String getAidForAppType(int);
     method public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int);
     method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
     method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int);
@@ -5405,6 +5454,8 @@
     method public deprecated boolean getDataEnabled();
     method public deprecated boolean getDataEnabled(int);
     method public boolean getEmergencyCallbackMode();
+    method public java.lang.String getIsimDomain();
+    method public int getPreferredNetworkType(int);
     method public int getSimApplicationState();
     method public int getSimCardState();
     method public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms();
@@ -5414,10 +5465,7 @@
     method public boolean handlePinMmi(java.lang.String);
     method public boolean handlePinMmiForSubscriber(int, java.lang.String);
     method public boolean isDataConnectivityPossible();
-    method public deprecated boolean isIdle();
-    method public deprecated boolean isOffhook();
     method public deprecated boolean isRadioOn();
-    method public deprecated boolean isRinging();
     method public boolean isVideoCallingEnabled();
     method public deprecated boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle);
     method public boolean needsOtaServiceProvisioning();
@@ -5431,7 +5479,6 @@
     method public void setSimPowerStateForSlot(int, int);
     method public deprecated void setVisualVoicemailEnabled(android.telecom.PhoneAccountHandle, boolean);
     method public void setVoiceActivationState(int);
-    method public deprecated void silenceRinger();
     method public boolean supplyPin(java.lang.String);
     method public int[] supplyPinReportResult(java.lang.String);
     method public boolean supplyPuk(java.lang.String, java.lang.String);
@@ -5449,6 +5496,29 @@
     field public static final java.lang.String EXTRA_SIM_STATE = "android.telephony.extra.SIM_STATE";
     field public static final java.lang.String EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL = "android.telephony.extra.VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL";
     field public static final java.lang.String EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING = "android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING";
+    field public static final int NETWORK_MODE_CDMA_EVDO = 4; // 0x4
+    field public static final int NETWORK_MODE_CDMA_NO_EVDO = 5; // 0x5
+    field public static final int NETWORK_MODE_EVDO_NO_CDMA = 6; // 0x6
+    field public static final int NETWORK_MODE_GLOBAL = 7; // 0x7
+    field public static final int NETWORK_MODE_GSM_ONLY = 1; // 0x1
+    field public static final int NETWORK_MODE_GSM_UMTS = 3; // 0x3
+    field public static final int NETWORK_MODE_LTE_CDMA_EVDO = 8; // 0x8
+    field public static final int NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA = 10; // 0xa
+    field public static final int NETWORK_MODE_LTE_GSM_WCDMA = 9; // 0x9
+    field public static final int NETWORK_MODE_LTE_ONLY = 11; // 0xb
+    field public static final int NETWORK_MODE_LTE_TDSCDMA = 15; // 0xf
+    field public static final int NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 22; // 0x16
+    field public static final int NETWORK_MODE_LTE_TDSCDMA_GSM = 17; // 0x11
+    field public static final int NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA = 20; // 0x14
+    field public static final int NETWORK_MODE_LTE_TDSCDMA_WCDMA = 19; // 0x13
+    field public static final int NETWORK_MODE_LTE_WCDMA = 12; // 0xc
+    field public static final int NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 21; // 0x15
+    field public static final int NETWORK_MODE_TDSCDMA_GSM = 16; // 0x10
+    field public static final int NETWORK_MODE_TDSCDMA_GSM_WCDMA = 18; // 0x12
+    field public static final int NETWORK_MODE_TDSCDMA_ONLY = 13; // 0xd
+    field public static final int NETWORK_MODE_TDSCDMA_WCDMA = 14; // 0xe
+    field public static final int NETWORK_MODE_WCDMA_ONLY = 2; // 0x2
+    field public static final int NETWORK_MODE_WCDMA_PREF = 0; // 0x0
     field public static final int SIM_ACTIVATION_STATE_ACTIVATED = 2; // 0x2
     field public static final int SIM_ACTIVATION_STATE_ACTIVATING = 1; // 0x1
     field public static final int SIM_ACTIVATION_STATE_DEACTIVATED = 3; // 0x3
@@ -5784,6 +5854,7 @@
     field public static final java.lang.String EXTRA_CODEC = "Codec";
     field public static final java.lang.String EXTRA_DIALSTRING = "dialstring";
     field public static final java.lang.String EXTRA_DISPLAY_TEXT = "DisplayText";
+    field public static final java.lang.String EXTRA_E_CALL = "e_call";
     field public static final java.lang.String EXTRA_IS_CALL_PULL = "CallPull";
     field public static final java.lang.String EXTRA_OI = "oi";
     field public static final java.lang.String EXTRA_OIR = "oir";
@@ -6528,6 +6599,17 @@
     method public int setTempFileRootDirectory(int, java.lang.String) throws android.os.RemoteException;
   }
 
+  public class MbmsGroupCallServiceBase extends android.app.Service {
+    ctor public MbmsGroupCallServiceBase();
+    method public void dispose(int) throws android.os.RemoteException;
+    method public int initialize(android.telephony.mbms.MbmsGroupCallSessionCallback, int) throws android.os.RemoteException;
+    method public void onAppCallbackDied(int, int);
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public int startGroupCall(int, long, int[], int[], android.telephony.mbms.GroupCallCallback);
+    method public void stopGroupCall(int, long);
+    method public void updateGroupCall(int, long, int[], int[]);
+  }
+
   public class MbmsStreamingServiceBase extends android.os.Binder {
     ctor public MbmsStreamingServiceBase();
     method public void dispose(int) throws android.os.RemoteException;
@@ -6572,6 +6654,10 @@
 
 package android.view {
 
+  public abstract class Window {
+    method public void addPrivateFlags(int);
+  }
+
   public abstract interface WindowManager implements android.view.ViewManager {
     method public abstract android.graphics.Region getCurrentImeTouchRegion();
   }
@@ -6579,6 +6665,7 @@
   public static class WindowManager.LayoutParams extends android.view.ViewGroup.LayoutParams implements android.os.Parcelable {
     method public final long getUserActivityTimeout();
     method public final void setUserActivityTimeout(long);
+    field public static final int PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS = 524288; // 0x80000
   }
 
 }
diff --git a/api/system-removed.txt b/api/system-removed.txt
index b88c760..2246562 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -143,3 +143,16 @@
 
 }
 
+package android.telephony {
+
+  public class TelephonyManager {
+    method public deprecated void answerRingingCall();
+    method public deprecated boolean endCall();
+    method public deprecated boolean isIdle();
+    method public deprecated boolean isOffhook();
+    method public deprecated boolean isRinging();
+    method public deprecated void silenceRinger();
+  }
+
+}
+
diff --git a/api/test-current.txt b/api/test-current.txt
index 28e9734..9567616 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -259,6 +259,7 @@
   }
 
   public abstract class Context {
+    method public android.content.Context createPackageContextAsUser(java.lang.String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract java.lang.String getOpPackageName();
     method public android.os.UserHandle getUser();
     method public int getUserId();
@@ -765,6 +766,8 @@
     method public static int getAppId(int);
     method public int getIdentifier();
     method public static boolean isApp(int);
+    field public static final android.os.UserHandle ALL;
+    field public static final android.os.UserHandle CURRENT;
     field public static final android.os.UserHandle SYSTEM;
   }
 
@@ -929,6 +932,13 @@
     field public static final android.net.Uri ENTERPRISE_CONTENT_URI;
   }
 
+  public static final class ContactsContract.RawContacts implements android.provider.BaseColumns android.provider.ContactsContract.ContactNameColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.RawContactsColumns android.provider.ContactsContract.SyncColumns {
+    field public static final android.net.Uri RAW_CONTACTS_NOTIFICATION_DELETE_URI;
+    field public static final android.net.Uri RAW_CONTACTS_NOTIFICATION_INSERT_URI;
+    field public static final android.net.Uri RAW_CONTACTS_NOTIFICATION_UPDATE_URI;
+    field public static final android.net.Uri RAW_CONTACTS_NOTIFICATION_URI;
+  }
+
   public static final class ContactsContract.RawContactsEntity implements android.provider.BaseColumns android.provider.ContactsContract.DataColumns android.provider.ContactsContract.RawContactsColumns {
     field public static final android.net.Uri CORP_CONTENT_URI;
   }
@@ -1178,6 +1188,10 @@
     field public static final java.lang.String MBMS_DOWNLOAD_SERVICE_OVERRIDE_METADATA = "mbms-download-service-override";
   }
 
+  public class MbmsGroupCallSession implements java.lang.AutoCloseable {
+    field public static final java.lang.String MBMS_GROUP_CALL_SERVICE_OVERRIDE_METADATA = "mbms-group-call-service-override";
+  }
+
   public class MbmsStreamingSession implements java.lang.AutoCloseable {
     field public static final java.lang.String MBMS_STREAMING_SERVICE_OVERRIDE_METADATA = "mbms-streaming-service-override";
   }
@@ -1247,6 +1261,17 @@
     method public int setTempFileRootDirectory(int, java.lang.String) throws android.os.RemoteException;
   }
 
+  public class MbmsGroupCallServiceBase extends android.app.Service {
+    ctor public MbmsGroupCallServiceBase();
+    method public void dispose(int) throws android.os.RemoteException;
+    method public int initialize(android.telephony.mbms.MbmsGroupCallSessionCallback, int) throws android.os.RemoteException;
+    method public void onAppCallbackDied(int, int);
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public int startGroupCall(int, long, int[], int[], android.telephony.mbms.GroupCallCallback);
+    method public void stopGroupCall(int, long);
+    method public void updateGroupCall(int, long, int[], int[]);
+  }
+
   public class MbmsStreamingServiceBase extends android.os.Binder {
     ctor public MbmsStreamingServiceBase();
     method public void dispose(int) throws android.os.RemoteException;
diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java
index 36e51b9..12fb4a3 100644
--- a/cmds/content/src/com/android/commands/content/Content.java
+++ b/cmds/content/src/com/android/commands/content/Content.java
@@ -470,7 +470,8 @@
                     onExecute(provider);
                 } finally {
                     if (provider != null) {
-                        activityManager.removeContentProviderExternal(providerName, token);
+                        activityManager.removeContentProviderExternalAsUser(
+                                providerName, token, mUserId);
                     }
                 }
             } catch (Exception e) {
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 87799b3..cd48af9 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -407,7 +407,19 @@
 
 WorkerThreadSection::~WorkerThreadSection() {}
 
+void sigpipe_handler(int signum) {
+    if (signum == SIGPIPE) {
+        ALOGE("Wrote to a broken pipe\n");
+    } else {
+        ALOGE("Received unexpected signal: %d\n", signum);
+    }
+}
+
 static void* worker_thread_func(void* cookie) {
+    // Don't crash the service if we write to a closed pipe (which can happen if
+    // dumping times out).
+    signal(SIGPIPE, sigpipe_handler);
+
     WorkerThreadData* data = (WorkerThreadData*)cookie;
     status_t err = data->section->BlockingCall(data->pipe.writeFd().get());
 
@@ -486,6 +498,7 @@
             }
         }
     }
+
     write_section_stats(requests->sectionStats(this->id), buffer);
     if (timedOut || buffer.timedOut()) {
         ALOGW("[%s] timed out", this->name.string());
@@ -773,7 +786,10 @@
         }
     }
     gLastLogsRetrieved[mLogID] = lastTimestamp;
-    proto.flush(pipeWriteFd);
+    if (!proto.flush(pipeWriteFd) && errno == EPIPE) {
+        ALOGE("[%s] wrote to a broken pipe\n", this->name.string());
+        return EPIPE;
+    }
     return NO_ERROR;
 }
 
@@ -875,7 +891,7 @@
             break;
         }
         if (cStatus != NO_ERROR) {
-            ALOGE("TombstoneSection '%s' child had an issue: %s\n", this->name.string(), strerror(-cStatus));
+            ALOGE("[%s] child had an issue: %s\n", this->name.string(), strerror(-cStatus));
         }
 
         auto dump = std::make_unique<char[]>(buffer.size());
@@ -894,7 +910,13 @@
         dumpPipe.readFd().reset();
     }
 
-    proto.flush(pipeWriteFd);
+    if (!proto.flush(pipeWriteFd) && errno == EPIPE) {
+        ALOGE("[%s] wrote to a broken pipe\n", this->name.string());
+        if (err != NO_ERROR) {
+            return EPIPE;
+        }
+    }
+
     return err;
 }
 
diff --git a/cmds/incidentd/src/Section.h b/cmds/incidentd/src/Section.h
index 302b4ef..86d956f 100644
--- a/cmds/incidentd/src/Section.h
+++ b/cmds/incidentd/src/Section.h
@@ -171,7 +171,7 @@
  */
 class TombstoneSection : public WorkerThreadSection {
 public:
-    TombstoneSection(int id, const char* type, int64_t timeoutMs = 30000 /* 30 seconds */);
+    TombstoneSection(int id, const char* type, int64_t timeoutMs = 120000 /* 2 minutes */);
     virtual ~TombstoneSection();
 
     virtual status_t BlockingCall(int pipeWriteFd) const;
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index b11e843..d334f96 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -198,8 +198,7 @@
 
     sp<GraphicBuffer> outBuffer;
     status_t result = ScreenshotClient::capture(display, Rect(), 0 /* reqWidth */,
-            0 /* reqHeight */, INT32_MIN, INT32_MAX, /* all layers */ false, captureOrientation,
-            &outBuffer);
+            0 /* reqHeight */, false, captureOrientation, &outBuffer);
     if (result != NO_ERROR) {
         close(fd);
         return 1;
@@ -207,7 +206,14 @@
 
     result = outBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &base);
 
-    if (base == NULL) {
+    if (base == nullptr || result != NO_ERROR) {
+        String8 reason;
+        if (base == nullptr) {
+            reason = "Failed to write to buffer";
+        } else {
+            reason.appendFormat("Error Code: %d", result);
+        }
+        fprintf(stderr, "Failed to take screenshot (%s)\n", reason.c_str());
         close(fd);
         return 1;
     }
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 5e87ef6..d3496ed 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -67,7 +67,9 @@
     src/subscriber/SubscriberReporter.cpp \
     src/HashableDimensionKey.cpp \
     src/guardrail/StatsdStats.cpp \
-    src/socket/StatsSocketListener.cpp
+    src/socket/StatsSocketListener.cpp \
+    src/shell/ShellSubscriber.cpp \
+    src/shell/shell_config.proto
 
 # TODO(b/110563449): Once statsd is using a blueprint file, migrate to the proper filegroups.
 statsd_common_src += \
@@ -144,10 +146,10 @@
 LOCAL_MODULE_CLASS := EXECUTABLES
 
 # Enable sanitizer ONLY on eng builds.
-ifeq ($(TARGET_BUILD_VARIANT),eng)
-    LOCAL_CLANG := true
-    LOCAL_SANITIZE := address
-endif
+#ifeq ($(TARGET_BUILD_VARIANT),eng)
+#    LOCAL_CLANG := true
+#    LOCAL_SANITIZE := address
+#endif
 
 # Add a flag to enable stats log printing from statsd on debug builds.
 ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT)))
diff --git a/cmds/statsd/src/FieldValue.cpp b/cmds/statsd/src/FieldValue.cpp
index 7b6d29b..fc1a61c 100644
--- a/cmds/statsd/src/FieldValue.cpp
+++ b/cmds/statsd/src/FieldValue.cpp
@@ -147,6 +147,9 @@
         case STRING:
             str_value = from.str_value;
             break;
+        case STORAGE:
+            storage_value = from.storage_value;
+            break;
         default:
             break;
     }
@@ -164,6 +167,8 @@
             return std::to_string(double_value) + "[D]";
         case STRING:
             return str_value + "[S]";
+        case STORAGE:
+            return "bytes of size " + std::to_string(storage_value.size()) + "[ST]";
         default:
             return "[UNKNOWN]";
     }
@@ -183,6 +188,8 @@
             return double_value == that.double_value;
         case STRING:
             return str_value == that.str_value;
+        case STORAGE:
+            return storage_value == that.storage_value;
         default:
             return false;
     }
@@ -201,6 +208,8 @@
             return double_value != that.double_value;
         case STRING:
             return str_value != that.str_value;
+        case STORAGE:
+            return storage_value != that.storage_value;
         default:
             return false;
     }
@@ -220,6 +229,8 @@
             return double_value < that.double_value;
         case STRING:
             return str_value < that.str_value;
+        case STORAGE:
+            return storage_value < that.storage_value;
         default:
             return false;
     }
@@ -239,6 +250,8 @@
             return double_value > that.double_value;
         case STRING:
             return str_value > that.str_value;
+        case STORAGE:
+            return storage_value > that.storage_value;
         default:
             return false;
     }
@@ -258,6 +271,8 @@
             return double_value >= that.double_value;
         case STRING:
             return str_value >= that.str_value;
+        case STORAGE:
+            return storage_value >= that.storage_value;
         default:
             return false;
     }
@@ -274,6 +289,11 @@
         return v;
     }
 
+    if (type == STORAGE) {
+        ALOGE("Can't operate on storage value type");
+        return v;
+    }
+
     switch (type) {
         case INT:
             v.setInt(int_value - that.int_value);
@@ -311,6 +331,9 @@
         case STRING:
             str_value = that.str_value;
             break;
+        case STORAGE:
+            storage_value = that.storage_value;
+            break;
         default:
             break;
     }
@@ -326,6 +349,10 @@
         ALOGE("Can't operate on string value type");
         return *this;
     }
+    if (type == STORAGE) {
+        ALOGE("Can't operate on storage value type");
+        return *this;
+    }
 
     switch (type) {
         case INT:
diff --git a/cmds/statsd/src/FieldValue.h b/cmds/statsd/src/FieldValue.h
index b1b885e..77163f9 100644
--- a/cmds/statsd/src/FieldValue.h
+++ b/cmds/statsd/src/FieldValue.h
@@ -32,7 +32,7 @@
 const int32_t kClearLastBitDeco = 0x7f;
 const int32_t kClearAllPositionMatcherMask = 0xffff00ff;
 
-enum Type { UNKNOWN, INT, LONG, FLOAT, DOUBLE, STRING };
+enum Type { UNKNOWN, INT, LONG, FLOAT, DOUBLE, STRING, STORAGE };
 
 int32_t getEncodedField(int32_t pos[], int32_t depth, bool includeDepth);
 
@@ -293,6 +293,11 @@
         type = STRING;
     }
 
+    Value(const std::vector<uint8_t>& v) {
+        storage_value = v;
+        type = STORAGE;
+    }
+
     void setInt(int32_t v) {
         int_value = v;
         type = INT;
@@ -320,6 +325,7 @@
         double double_value;
     };
     std::string str_value;
+    std::vector<uint8_t> storage_value;
 
     Type type;
 
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 8e02f9c..f4c70be 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -257,12 +257,18 @@
     return it->second->byteSize();
 }
 
-void StatsLogProcessor::dumpStates(FILE* out, bool verbose) {
+void StatsLogProcessor::dumpStates(int out, bool verbose) {
     std::lock_guard<std::mutex> lock(mMetricsMutex);
-    fprintf(out, "MetricsManager count: %lu\n", (unsigned long)mMetricsManagers.size());
-    for (auto metricsManager : mMetricsManagers) {
-        metricsManager.second->dumpStates(out, verbose);
+    FILE* fout = fdopen(out, "w");
+    if (fout == NULL) {
+        return;
     }
+    fprintf(fout, "MetricsManager count: %lu\n", (unsigned long)mMetricsManagers.size());
+    for (auto metricsManager : mMetricsManagers) {
+        metricsManager.second->dumpStates(fout, verbose);
+    }
+
+    fclose(fout);
 }
 
 /*
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index df80b8e..4091d95 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -83,7 +83,7 @@
         return mUidMap;
     }
 
-    void dumpStates(FILE* out, bool verbose);
+    void dumpStates(int outFd, bool verbose);
 
     void informPullAlarmFired(const int64_t timestampNs);
 
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 9a79345..2ef1169 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -34,13 +34,14 @@
 #include <dirent.h>
 #include <frameworks/base/cmds/statsd/src/statsd_config.pb.h>
 #include <private/android_filesystem_config.h>
-#include <utils/Looper.h>
-#include <utils/String16.h>
 #include <statslog.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/system_properties.h>
 #include <unistd.h>
+#include <utils/Looper.h>
+#include <utils/String16.h>
+#include <chrono>
 
 using namespace android;
 
@@ -214,30 +215,8 @@
             sp<IResultReceiver> resultReceiver =
                     IResultReceiver::asInterface(data.readStrongBinder());
 
-            FILE* fin = fdopen(in, "r");
-            FILE* fout = fdopen(out, "w");
-            FILE* ferr = fdopen(err, "w");
-
-            if (fin == NULL || fout == NULL || ferr == NULL) {
-                resultReceiver->send(NO_MEMORY);
-            } else {
-                err = command(fin, fout, ferr, args);
-                resultReceiver->send(err);
-            }
-
-            if (fin != NULL) {
-                fflush(fin);
-                fclose(fin);
-            }
-            if (fout != NULL) {
-                fflush(fout);
-                fclose(fout);
-            }
-            if (fout != NULL) {
-                fflush(ferr);
-                fclose(ferr);
-            }
-
+            err = command(in, out, err, args, resultReceiver);
+            resultReceiver->send(err);
             return NO_ERROR;
         }
         default: { return BnStatsManager::onTransact(code, data, reply, flags); }
@@ -251,10 +230,6 @@
     if (!checkCallingPermission(String16(kPermissionDump))) {
         return PERMISSION_DENIED;
     }
-    FILE* out = fdopen(fd, "w");
-    if (out == NULL) {
-        return NO_MEMORY;  // the fd is already open
-    }
 
     bool verbose = false;
     bool proto = false;
@@ -265,21 +240,20 @@
         proto = true;
     }
 
-    dump_impl(out, verbose, proto);
+    dump_impl(fd, verbose, proto);
 
-    fclose(out);
     return NO_ERROR;
 }
 
 /**
  * Write debugging data about statsd in text or proto format.
  */
-void StatsService::dump_impl(FILE* out, bool verbose, bool proto) {
+void StatsService::dump_impl(int out, bool verbose, bool proto) {
     if (proto) {
         vector<uint8_t> data;
         StatsdStats::getInstance().dumpStats(&data, false); // does not reset statsdStats.
         for (size_t i = 0; i < data.size(); i ++) {
-            fprintf(out, "%c", data[i]);
+            dprintf(out, "%c", data[i]);
         }
     } else {
         StatsdStats::getInstance().dumpStats(out);
@@ -290,7 +264,8 @@
 /**
  * Implementation of the adb shell cmd stats command.
  */
-status_t StatsService::command(FILE* in, FILE* out, FILE* err, Vector<String8>& args) {
+status_t StatsService::command(int in, int out, int err, Vector<String8>& args,
+                               sp<IResultReceiver> resultReceiver) {
     uid_t uid = IPCThreadState::self()->getCallingUid();
     if (uid != AID_ROOT && uid != AID_SHELL) {
         return PERMISSION_DENIED;
@@ -342,97 +317,106 @@
         if (!args[0].compare(String8("print-logs"))) {
             return cmd_print_logs(out, args);
         }
+        if (!args[0].compare(String8("data-subscribe"))) {
+            if (mShellSubscriber == nullptr) {
+                mShellSubscriber = new ShellSubscriber(mUidMap);
+            }
+            mShellSubscriber->startNewSubscription(in, out, resultReceiver);
+            return NO_ERROR;
+        }
     }
 
     print_cmd_help(out);
     return NO_ERROR;
 }
 
-void StatsService::print_cmd_help(FILE* out) {
-    fprintf(out,
+void StatsService::print_cmd_help(int out) {
+    dprintf(out,
             "usage: adb shell cmd stats print-stats-log [tag_required] "
             "[timestamp_nsec_optional]\n");
-    fprintf(out, "\n");
-    fprintf(out, "\n");
-    fprintf(out, "usage: adb shell cmd stats meminfo\n");
-    fprintf(out, "\n");
-    fprintf(out, "  Prints the malloc debug information. You need to run the following first: \n");
-    fprintf(out, "   # adb shell stop\n");
-    fprintf(out, "   # adb shell setprop libc.debug.malloc.program statsd \n");
-    fprintf(out, "   # adb shell setprop libc.debug.malloc.options backtrace \n");
-    fprintf(out, "   # adb shell start\n");
-    fprintf(out, "\n");
-    fprintf(out, "\n");
-    fprintf(out, "usage: adb shell cmd stats print-uid-map [PKG]\n");
-    fprintf(out, "\n");
-    fprintf(out, "  Prints the UID, app name, version mapping.\n");
-    fprintf(out, "  PKG           Optional package name to print the uids of the package\n");
-    fprintf(out, "\n");
-    fprintf(out, "\n");
-    fprintf(out, "usage: adb shell cmd stats pull-source [int] \n");
-    fprintf(out, "\n");
-    fprintf(out, "  Prints the output of a pulled metrics source (int indicates source)\n");
-    fprintf(out, "\n");
-    fprintf(out, "\n");
-    fprintf(out, "usage: adb shell cmd stats write-to-disk \n");
-    fprintf(out, "\n");
-    fprintf(out, "  Flushes all data on memory to disk.\n");
-    fprintf(out, "\n");
-    fprintf(out, "\n");
-    fprintf(out, "usage: adb shell cmd stats log-app-breadcrumb [UID] LABEL STATE\n");
-    fprintf(out, "  Writes an AppBreadcrumbReported event to the statslog buffer.\n");
-    fprintf(out, "  UID           The uid to use. It is only possible to pass a UID\n");
-    fprintf(out, "                parameter on eng builds. If UID is omitted the calling\n");
-    fprintf(out, "                uid is used.\n");
-    fprintf(out, "  LABEL         Integer in [0, 15], as per atoms.proto.\n");
-    fprintf(out, "  STATE         Integer in [0, 3], as per atoms.proto.\n");
-    fprintf(out, "\n");
-    fprintf(out, "\n");
-    fprintf(out, "usage: adb shell cmd stats config remove [UID] [NAME]\n");
-    fprintf(out, "usage: adb shell cmd stats config update [UID] NAME\n");
-    fprintf(out, "\n");
-    fprintf(out, "  Adds, updates or removes a configuration. The proto should be in\n");
-    fprintf(out, "  wire-encoded protobuf format and passed via stdin. If no UID and name is\n");
-    fprintf(out, "  provided, then all configs will be removed from memory and disk.\n");
-    fprintf(out, "\n");
-    fprintf(out, "  UID           The uid to use. It is only possible to pass the UID\n");
-    fprintf(out, "                parameter on eng builds. If UID is omitted the calling\n");
-    fprintf(out, "                uid is used.\n");
-    fprintf(out, "  NAME          The per-uid name to use\n");
-    fprintf(out, "\n");
-    fprintf(out, "\n              *Note: If both UID and NAME are omitted then all configs will\n");
-    fprintf(out, "\n                     be removed from memory and disk!\n");
-    fprintf(out, "\n");
-    fprintf(out, "usage: adb shell cmd stats dump-report [UID] NAME [--include_current_bucket] [--proto]\n");
-    fprintf(out, "  Dump all metric data for a configuration.\n");
-    fprintf(out, "  UID           The uid of the configuration. It is only possible to pass\n");
-    fprintf(out, "                the UID parameter on eng builds. If UID is omitted the\n");
-    fprintf(out, "                calling uid is used.\n");
-    fprintf(out, "  NAME          The name of the configuration\n");
-    fprintf(out, "  --proto       Print proto binary.\n");
-    fprintf(out, "\n");
-    fprintf(out, "\n");
-    fprintf(out, "usage: adb shell cmd stats send-broadcast [UID] NAME\n");
-    fprintf(out, "  Send a broadcast that triggers the subscriber to fetch metrics.\n");
-    fprintf(out, "  UID           The uid of the configuration. It is only possible to pass\n");
-    fprintf(out, "                the UID parameter on eng builds. If UID is omitted the\n");
-    fprintf(out, "                calling uid is used.\n");
-    fprintf(out, "  NAME          The name of the configuration\n");
-    fprintf(out, "\n");
-    fprintf(out, "\n");
-    fprintf(out, "usage: adb shell cmd stats print-stats\n");
-    fprintf(out, "  Prints some basic stats.\n");
-    fprintf(out, "  --proto       Print proto binary instead of string format.\n");
-    fprintf(out, "\n");
-    fprintf(out, "\n");
-    fprintf(out, "usage: adb shell cmd stats clear-puller-cache\n");
-    fprintf(out, "  Clear cached puller data.\n");
-    fprintf(out, "\n");
-    fprintf(out, "usage: adb shell cmd stats print-logs\n");
-    fprintf(out, "      Only works on eng build\n");
+    dprintf(out, "\n");
+    dprintf(out, "\n");
+    dprintf(out, "usage: adb shell cmd stats meminfo\n");
+    dprintf(out, "\n");
+    dprintf(out, "  Prints the malloc debug information. You need to run the following first: \n");
+    dprintf(out, "   # adb shell stop\n");
+    dprintf(out, "   # adb shell setprop libc.debug.malloc.program statsd \n");
+    dprintf(out, "   # adb shell setprop libc.debug.malloc.options backtrace \n");
+    dprintf(out, "   # adb shell start\n");
+    dprintf(out, "\n");
+    dprintf(out, "\n");
+    dprintf(out, "usage: adb shell cmd stats print-uid-map [PKG]\n");
+    dprintf(out, "\n");
+    dprintf(out, "  Prints the UID, app name, version mapping.\n");
+    dprintf(out, "  PKG           Optional package name to print the uids of the package\n");
+    dprintf(out, "\n");
+    dprintf(out, "\n");
+    dprintf(out, "usage: adb shell cmd stats pull-source [int] \n");
+    dprintf(out, "\n");
+    dprintf(out, "  Prints the output of a pulled metrics source (int indicates source)\n");
+    dprintf(out, "\n");
+    dprintf(out, "\n");
+    dprintf(out, "usage: adb shell cmd stats write-to-disk \n");
+    dprintf(out, "\n");
+    dprintf(out, "  Flushes all data on memory to disk.\n");
+    dprintf(out, "\n");
+    dprintf(out, "\n");
+    dprintf(out, "usage: adb shell cmd stats log-app-breadcrumb [UID] LABEL STATE\n");
+    dprintf(out, "  Writes an AppBreadcrumbReported event to the statslog buffer.\n");
+    dprintf(out, "  UID           The uid to use. It is only possible to pass a UID\n");
+    dprintf(out, "                parameter on eng builds. If UID is omitted the calling\n");
+    dprintf(out, "                uid is used.\n");
+    dprintf(out, "  LABEL         Integer in [0, 15], as per atoms.proto.\n");
+    dprintf(out, "  STATE         Integer in [0, 3], as per atoms.proto.\n");
+    dprintf(out, "\n");
+    dprintf(out, "\n");
+    dprintf(out, "usage: adb shell cmd stats config remove [UID] [NAME]\n");
+    dprintf(out, "usage: adb shell cmd stats config update [UID] NAME\n");
+    dprintf(out, "\n");
+    dprintf(out, "  Adds, updates or removes a configuration. The proto should be in\n");
+    dprintf(out, "  wire-encoded protobuf format and passed via stdin. If no UID and name is\n");
+    dprintf(out, "  provided, then all configs will be removed from memory and disk.\n");
+    dprintf(out, "\n");
+    dprintf(out, "  UID           The uid to use. It is only possible to pass the UID\n");
+    dprintf(out, "                parameter on eng builds. If UID is omitted the calling\n");
+    dprintf(out, "                uid is used.\n");
+    dprintf(out, "  NAME          The per-uid name to use\n");
+    dprintf(out, "\n");
+    dprintf(out, "\n              *Note: If both UID and NAME are omitted then all configs will\n");
+    dprintf(out, "\n                     be removed from memory and disk!\n");
+    dprintf(out, "\n");
+    dprintf(out,
+            "usage: adb shell cmd stats dump-report [UID] NAME [--include_current_bucket] "
+            "[--proto]\n");
+    dprintf(out, "  Dump all metric data for a configuration.\n");
+    dprintf(out, "  UID           The uid of the configuration. It is only possible to pass\n");
+    dprintf(out, "                the UID parameter on eng builds. If UID is omitted the\n");
+    dprintf(out, "                calling uid is used.\n");
+    dprintf(out, "  NAME          The name of the configuration\n");
+    dprintf(out, "  --proto       Print proto binary.\n");
+    dprintf(out, "\n");
+    dprintf(out, "\n");
+    dprintf(out, "usage: adb shell cmd stats send-broadcast [UID] NAME\n");
+    dprintf(out, "  Send a broadcast that triggers the subscriber to fetch metrics.\n");
+    dprintf(out, "  UID           The uid of the configuration. It is only possible to pass\n");
+    dprintf(out, "                the UID parameter on eng builds. If UID is omitted the\n");
+    dprintf(out, "                calling uid is used.\n");
+    dprintf(out, "  NAME          The name of the configuration\n");
+    dprintf(out, "\n");
+    dprintf(out, "\n");
+    dprintf(out, "usage: adb shell cmd stats print-stats\n");
+    dprintf(out, "  Prints some basic stats.\n");
+    dprintf(out, "  --proto       Print proto binary instead of string format.\n");
+    dprintf(out, "\n");
+    dprintf(out, "\n");
+    dprintf(out, "usage: adb shell cmd stats clear-puller-cache\n");
+    dprintf(out, "  Clear cached puller data.\n");
+    dprintf(out, "\n");
+    dprintf(out, "usage: adb shell cmd stats print-logs\n");
+    dprintf(out, "      Only works on eng build\n");
 }
 
-status_t StatsService::cmd_trigger_broadcast(FILE* out, Vector<String8>& args) {
+status_t StatsService::cmd_trigger_broadcast(int out, Vector<String8>& args) {
     string name;
     bool good = false;
     int uid;
@@ -456,9 +440,9 @@
                 }
             }
         } else {
-            fprintf(out,
+            dprintf(out,
                     "The metrics can only be dumped for other UIDs on eng or userdebug "
-                            "builds.\n");
+                    "builds.\n");
         }
     }
     if (!good) {
@@ -481,7 +465,7 @@
     return NO_ERROR;
 }
 
-status_t StatsService::cmd_config(FILE* in, FILE* out, FILE* err, Vector<String8>& args) {
+status_t StatsService::cmd_config(int in, int out, int err, Vector<String8>& args) {
     const int argCount = args.size();
     if (argCount >= 2) {
         if (args[1] == "update" || args[1] == "remove") {
@@ -508,7 +492,7 @@
                         }
                     }
                 } else {
-                    fprintf(err,
+                    dprintf(err,
                             "The config can only be set for other UIDs on eng or userdebug "
                             "builds.\n");
                 }
@@ -526,21 +510,21 @@
                 char* endp;
                 int64_t configID = strtoll(name.c_str(), &endp, 10);
                 if (endp == name.c_str() || *endp != '\0') {
-                    fprintf(err, "Error parsing config ID.\n");
+                    dprintf(err, "Error parsing config ID.\n");
                     return UNKNOWN_ERROR;
                 }
 
                 // Read stream into buffer.
                 string buffer;
-                if (!android::base::ReadFdToString(fileno(in), &buffer)) {
-                    fprintf(err, "Error reading stream for StatsConfig.\n");
+                if (!android::base::ReadFdToString(in, &buffer)) {
+                    dprintf(err, "Error reading stream for StatsConfig.\n");
                     return UNKNOWN_ERROR;
                 }
 
                 // Parse buffer.
                 StatsdConfig config;
                 if (!config.ParseFromString(buffer)) {
-                    fprintf(err, "Error parsing proto stream for StatsConfig.\n");
+                    dprintf(err, "Error parsing proto stream for StatsConfig.\n");
                     return UNKNOWN_ERROR;
                 }
 
@@ -562,7 +546,7 @@
     return UNKNOWN_ERROR;
 }
 
-status_t StatsService::cmd_dump_report(FILE* out, FILE* err, const Vector<String8>& args) {
+status_t StatsService::cmd_dump_report(int out, int err, const Vector<String8>& args) {
     if (mProcessor != nullptr) {
         int argCount = args.size();
         bool good = false;
@@ -597,7 +581,7 @@
                     }
                 }
             } else {
-                fprintf(out,
+                dprintf(out,
                         "The metrics can only be dumped for other UIDs on eng or userdebug "
                         "builds.\n");
             }
@@ -608,11 +592,11 @@
                                      includeCurrentBucket, ADB_DUMP, &data);
             if (proto) {
                 for (size_t i = 0; i < data.size(); i ++) {
-                    fprintf(out, "%c", data[i]);
+                    dprintf(out, "%c", data[i]);
                 }
             } else {
-                fprintf(out, "Dump report for Config [%d,%s]\n", uid, name.c_str());
-                fprintf(out, "See the StatsLogReport in logcat...\n");
+                dprintf(out, "Dump report for Config [%d,%s]\n", uid, name.c_str());
+                dprintf(out, "See the StatsLogReport in logcat...\n");
             }
             return android::OK;
         } else {
@@ -621,12 +605,12 @@
             return UNKNOWN_ERROR;
         }
     } else {
-        fprintf(out, "Log processor does not exist...\n");
+        dprintf(out, "Log processor does not exist...\n");
         return UNKNOWN_ERROR;
     }
 }
 
-status_t StatsService::cmd_print_stats(FILE* out, const Vector<String8>& args) {
+status_t StatsService::cmd_print_stats(int out, const Vector<String8>& args) {
     int argCount = args.size();
     bool proto = false;
     if (!std::strcmp("--proto", args[argCount-1].c_str())) {
@@ -638,13 +622,13 @@
         vector<uint8_t> data;
         statsdStats.dumpStats(&data, false); // does not reset statsdStats.
         for (size_t i = 0; i < data.size(); i ++) {
-            fprintf(out, "%c", data[i]);
+            dprintf(out, "%c", data[i]);
         }
 
     } else {
         vector<ConfigKey> configs = mConfigManager->GetAllConfigKeys();
         for (const ConfigKey& key : configs) {
-            fprintf(out, "Config %s uses %zu bytes\n", key.ToString().c_str(),
+            dprintf(out, "Config %s uses %zu bytes\n", key.ToString().c_str(),
                     mProcessor->GetMetricsSize(key));
         }
         statsdStats.dumpStats(out);
@@ -652,29 +636,29 @@
     return NO_ERROR;
 }
 
-status_t StatsService::cmd_print_uid_map(FILE* out, const Vector<String8>& args) {
+status_t StatsService::cmd_print_uid_map(int out, const Vector<String8>& args) {
     if (args.size() > 1) {
         string pkg;
         pkg.assign(args[1].c_str(), args[1].size());
         auto uids = mUidMap->getAppUid(pkg);
-        fprintf(out, "%s -> [ ", pkg.c_str());
+        dprintf(out, "%s -> [ ", pkg.c_str());
         for (const auto& uid : uids) {
-            fprintf(out, "%d ", uid);
+            dprintf(out, "%d ", uid);
         }
-        fprintf(out, "]\n");
+        dprintf(out, "]\n");
     } else {
         mUidMap->printUidMap(out);
     }
     return NO_ERROR;
 }
 
-status_t StatsService::cmd_write_data_to_disk(FILE* out) {
-    fprintf(out, "Writing data to disk\n");
+status_t StatsService::cmd_write_data_to_disk(int out) {
+    dprintf(out, "Writing data to disk\n");
     mProcessor->WriteDataToDisk(ADB_DUMP);
     return NO_ERROR;
 }
 
-status_t StatsService::cmd_log_app_breadcrumb(FILE* out, const Vector<String8>& args) {
+status_t StatsService::cmd_log_app_breadcrumb(int out, const Vector<String8>& args) {
     bool good = false;
     int32_t uid;
     int32_t label;
@@ -695,13 +679,13 @@
             state = atoi(args[3].c_str());
             good = true;
         } else {
-            fprintf(out,
+            dprintf(out,
                     "Selecting a UID for writing AppBreadcrumb can only be done for other UIDs "
-                            "on eng or userdebug builds.\n");
+                    "on eng or userdebug builds.\n");
         }
     }
     if (good) {
-        fprintf(out, "Logging AppBreadcrumbReported(%d, %d, %d) to statslog.\n", uid, label, state);
+        dprintf(out, "Logging AppBreadcrumbReported(%d, %d, %d) to statslog.\n", uid, label, state);
         android::util::stats_write(android::util::APP_BREADCRUMB_REPORTED, uid, label, state);
     } else {
         print_cmd_help(out);
@@ -710,46 +694,46 @@
     return NO_ERROR;
 }
 
-status_t StatsService::cmd_print_pulled_metrics(FILE* out, const Vector<String8>& args) {
+status_t StatsService::cmd_print_pulled_metrics(int out, const Vector<String8>& args) {
     int s = atoi(args[1].c_str());
     vector<shared_ptr<LogEvent> > stats;
     if (mPullerManager->Pull(s, getElapsedRealtimeNs(), &stats)) {
         for (const auto& it : stats) {
-            fprintf(out, "Pull from %d: %s\n", s, it->ToString().c_str());
+            dprintf(out, "Pull from %d: %s\n", s, it->ToString().c_str());
         }
-        fprintf(out, "Pull from %d: Received %zu elements\n", s, stats.size());
+        dprintf(out, "Pull from %d: Received %zu elements\n", s, stats.size());
         return NO_ERROR;
     }
     return UNKNOWN_ERROR;
 }
 
-status_t StatsService::cmd_remove_all_configs(FILE* out) {
-    fprintf(out, "Removing all configs...\n");
+status_t StatsService::cmd_remove_all_configs(int out) {
+    dprintf(out, "Removing all configs...\n");
     VLOG("StatsService::cmd_remove_all_configs was called");
     mConfigManager->RemoveAllConfigs();
     StorageManager::deleteAllFiles(STATS_SERVICE_DIR);
     return NO_ERROR;
 }
 
-status_t StatsService::cmd_dump_memory_info(FILE* out) {
-    fprintf(out, "meminfo not available.\n");
+status_t StatsService::cmd_dump_memory_info(int out) {
+    dprintf(out, "meminfo not available.\n");
     return NO_ERROR;
 }
 
-status_t StatsService::cmd_clear_puller_cache(FILE* out) {
+status_t StatsService::cmd_clear_puller_cache(int out) {
     IPCThreadState* ipc = IPCThreadState::self();
     VLOG("StatsService::cmd_clear_puller_cache with Pid %i, Uid %i",
             ipc->getCallingPid(), ipc->getCallingUid());
     if (checkCallingPermission(String16(kPermissionDump))) {
         int cleared = mPullerManager->ForceClearPullerCache();
-        fprintf(out, "Puller removed %d cached data!\n", cleared);
+        dprintf(out, "Puller removed %d cached data!\n", cleared);
         return NO_ERROR;
     } else {
         return PERMISSION_DENIED;
     }
 }
 
-status_t StatsService::cmd_print_logs(FILE* out, const Vector<String8>& args) {
+status_t StatsService::cmd_print_logs(int out, const Vector<String8>& args) {
     IPCThreadState* ipc = IPCThreadState::self();
     VLOG("StatsService::cmd_print_logs with Pid %i, Uid %i", ipc->getCallingPid(),
          ipc->getCallingUid());
@@ -885,6 +869,9 @@
 
 void StatsService::OnLogEvent(LogEvent* event) {
     mProcessor->OnLogEvent(event);
+    if (mShellSubscriber != nullptr) {
+        mShellSubscriber->onLogEvent(*event);
+    }
 }
 
 Status StatsService::getData(int64_t key, const String16& packageName, vector<uint8_t>* output) {
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 613f509..0618927 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -24,6 +24,7 @@
 #include "external/StatsPullerManager.h"
 #include "logd/LogListener.h"
 #include "packages/UidMap.h"
+#include "shell/ShellSubscriber.h"
 #include "statscompanion_util.h"
 
 #include <android/os/BnStatsManager.h>
@@ -54,7 +55,8 @@
 
     virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
     virtual status_t dump(int fd, const Vector<String16>& args);
-    virtual status_t command(FILE* in, FILE* out, FILE* err, Vector<String8>& args);
+    virtual status_t command(int inFd, int outFd, int err, Vector<String8>& args,
+                             sp<IResultReceiver> resultReceiver);
 
     virtual Status systemRunning();
     virtual Status statsCompanionReady();
@@ -162,73 +164,73 @@
     /**
      * Text or proto output of dumpsys.
      */
-    void dump_impl(FILE* out, bool verbose, bool proto);
+    void dump_impl(int outFd, bool verbose, bool proto);
 
     /**
      * Print usage information for the commands
      */
-    void print_cmd_help(FILE* out);
+    void print_cmd_help(int out);
 
     /**
      * Trigger a broadcast.
      */
-    status_t cmd_trigger_broadcast(FILE* out, Vector<String8>& args);
+    status_t cmd_trigger_broadcast(int outFd, Vector<String8>& args);
 
     /**
      * Handle the config sub-command.
      */
-    status_t cmd_config(FILE* in, FILE* out, FILE* err, Vector<String8>& args);
+    status_t cmd_config(int inFd, int outFd, int err, Vector<String8>& args);
 
     /**
      * Prints some basic stats to std out.
      */
-    status_t cmd_print_stats(FILE* out, const Vector<String8>& args);
+    status_t cmd_print_stats(int outFd, const Vector<String8>& args);
 
     /**
      * Print the event log.
      */
-    status_t cmd_dump_report(FILE* out, FILE* err, const Vector<String8>& args);
+    status_t cmd_dump_report(int outFd, int err, const Vector<String8>& args);
 
     /**
      * Print the mapping of uids to package names.
      */
-    status_t cmd_print_uid_map(FILE* out, const Vector<String8>& args);
+    status_t cmd_print_uid_map(int outFd, const Vector<String8>& args);
 
     /**
      * Flush the data to disk.
      */
-    status_t cmd_write_data_to_disk(FILE* out);
+    status_t cmd_write_data_to_disk(int outFd);
 
     /**
      * Write an AppBreadcrumbReported event to the StatsLog buffer, as if calling
      * StatsLog.write(APP_BREADCRUMB_REPORTED).
      */
-    status_t cmd_log_app_breadcrumb(FILE* out, const Vector<String8>& args);
+    status_t cmd_log_app_breadcrumb(int outFd, const Vector<String8>& args);
 
     /**
      * Print contents of a pulled metrics source.
      */
-    status_t cmd_print_pulled_metrics(FILE* out, const Vector<String8>& args);
+    status_t cmd_print_pulled_metrics(int outFd, const Vector<String8>& args);
 
     /**
      * Removes all configs stored on disk and on memory.
      */
-    status_t cmd_remove_all_configs(FILE* out);
+    status_t cmd_remove_all_configs(int outFd);
 
     /*
      * Dump memory usage by statsd.
      */
-    status_t cmd_dump_memory_info(FILE* out);
+    status_t cmd_dump_memory_info(int outFd);
 
     /*
      * Clear all puller cached data
      */
-    status_t cmd_clear_puller_cache(FILE* out);
+    status_t cmd_clear_puller_cache(int outFd);
 
     /**
      * Print all stats logs received to logcat.
      */
-    status_t cmd_print_logs(FILE* out, const Vector<String8>& args);
+    status_t cmd_print_logs(int outFd, const Vector<String8>& args);
 
     /**
      * Adds a configuration after checking permissions and obtaining UID from binder call.
@@ -275,6 +277,8 @@
      */
     bool mEngBuild;
 
+    sp<ShellSubscriber> mShellSubscriber;
+
     FRIEND_TEST(StatsServiceTest, TestAddConfig_simple);
     FRIEND_TEST(StatsServiceTest, TestAddConfig_empty);
     FRIEND_TEST(StatsServiceTest, TestAddConfig_invalid);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 2c07431..85141ca 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -80,7 +80,8 @@
         BatteryLevelChanged battery_level_changed = 30;
         ChargingStateChanged charging_state_changed = 31;
         PluggedStateChanged plugged_state_changed = 32;
-        // 33 - 34 are available
+        InteractiveStateChanged interactive_state_changed = 33;
+        // 34 is available
         WakeupAlarmOccurred wakeup_alarm_occurred = 35;
         KernelWakeupReported kernel_wakeup_reported = 36;
         WifiLockStateChanged wifi_lock_state_changed = 37;
@@ -132,6 +133,11 @@
         KeyValuePairsAtom key_value_pairs_atom = 83;
         VibratorStateChanged vibrator_state_changed = 84;
         DeferredJobStatsReported deferred_job_stats_reported = 85;
+        ThermalThrottlingStateChanged thermal_throttling = 86;
+        FingerprintAcquired fingerprint_acquired = 87;
+        FingerprintAuthenticated fingerprint_authenticated = 88;
+        FingerprintErrorOccurred fingerprint_error_occurred = 89;
+        Notification notification = 90;
     }
 
     // Pulled events will start at field 10000.
@@ -166,11 +172,14 @@
         DirectoryUsage directory_usage = 10026;
         AppSize app_size = 10027;
         CategorySize category_size = 10028;
-        android.service.procstats.ProcessStatsSectionProto proc_stats = 10029;
+        BatteryVoltage battery_voltage = 10030;
+        NumFingerprints num_fingerprints = 10031;
+        ProcStats proc_stats = 10029;
     }
 
-    // DO NOT USE field numbers above 100,000 in AOSP. Field numbers above
-    // 100,000 are reserved for non-AOSP (e.g. OEMs) to use.
+    // DO NOT USE field numbers above 100,000 in AOSP.
+    // Field numbers 100,000 - 199,999 are reserved for non-AOSP (e.g. OEMs) to use.
+    // Field numbers 200,000 and above are reserved for future use; do not use them at all.
 }
 
 /**
@@ -229,6 +238,26 @@
  */
 
 /**
+ * Logs when the Thermal service HAL notifies the throttling start/stop events.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/stats/StatsCompanionService.java
+ */
+message ThermalThrottlingStateChanged {
+    optional android.os.TemperatureTypeEnum sensor_type = 1;
+
+    enum State {
+        UNKNOWN = 0;
+        START = 1;
+        STOP = 2;
+    }
+
+    optional State state = 2;
+
+    optional float temperature = 3;
+}
+
+/**
  * Logs when the screen state changes.
  *
  * Logged from:
@@ -410,9 +439,9 @@
  * Logs reporting of a ble scan finding results.
  *
  * Logged from:
- *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ *   packages/apps/Bluetooth/src/com/android/bluetooth/gatt/AppScanStats.java
  */
-// TODO: Consider changing to tracking per-scanner-id (log from AppScanStats).
+// TODO: Consider also tracking per-scanner-id.
 message BleScanResultReceived {
     repeated AttributionNode attribution_node = 1;
 
@@ -637,6 +666,20 @@
 }
 
 /**
+ * Logs when the device is interactive, according to the PowerManager Notifier.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/power/Notifier.java
+ */
+message InteractiveStateChanged {
+    enum State {
+        OFF = 0;
+        ON = 1;
+    }
+    optional State state = 1;
+}
+
+/**
  * Logs Battery Saver state change.
  *
  * Logged from:
@@ -726,6 +769,9 @@
 
     // Name of the wakeup alarm.
     optional string tag = 2;
+
+    // Name of source package (for historical reasons, since BatteryStats tracked it).
+    optional string package_name = 3;
 }
 
 /**
@@ -1810,6 +1856,123 @@
     optional android.os.statsd.EventType event_id = 2;
 }
 
+/**
+ * Logs when a fingerprint acquire event occurs.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+ */
+message FingerprintAcquired {
+    // The associated user. Eg: 0 for owners, 10+ for others.
+    // Defined in android/os/UserHandle.java
+    optional int32 user = 1;
+    // If this acquire is for a crypto fingerprint.
+    // e.g. Secure purchases, unlock password storage.
+    optional bool is_crypto = 2;
+}
+
+/**
+ * Logs when a fingerprint authentication event occurs.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+ */
+message FingerprintAuthenticated {
+    // The associated user. Eg: 0 for owners, 10+ for others.
+    // Defined in android/os/UserHandle.java
+    optional int32 user = 1;
+    // If this authentication is for a crypto fingerprint.
+    // e.g. Secure purchases, unlock password storage.
+    optional bool is_crypto = 2;
+    // Whether or not this authentication was successful.
+    optional bool is_authenticated = 3;
+}
+
+/**
+ * Logs when a fingerprint error occurs.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+ */
+message FingerprintErrorOccurred {
+    // The associated user. Eg: 0 for owners, 10+ for others.
+    // Defined in android/os/UserHandle.java
+    optional int32 user = 1;
+    // If this error is for a crypto fingerprint.
+    // e.g. Secure purchases, unlock password storage.
+    optional bool is_crypto = 2;
+
+    enum Error {
+        UNKNOWN = 0;
+        LOCKOUT = 1;
+        PERMANENT_LOCKOUT = 2;
+    }
+    // The type of error.
+    optional Error error = 3;
+}
+
+message Notification {
+
+    // Type of notification event.
+    enum Type {
+        TYPE_UNKNOWN = 0;
+        // Notification became visible to the user.
+        TYPE_OPEN = 1;
+        // Notification became hidden.
+        TYPE_CLOSE = 2;
+        // Notification switched to detail mode.
+        TYPE_DETAIL = 3;
+        // Notification was clicked.
+        TYPE_ACTION = 4;
+        // Notification was dismissed.
+        TYPE_DISMISS = 5;
+        // Notification switched to summary mode. The enum value of 14 is to
+        // match that of metrics_constants.
+        TYPE_COLLAPSE = 14;
+    }
+    optional Type type = 1;
+
+    // Package name associated with the notification.
+    optional string package_name = 2;
+
+    // Tag associated with notification.
+    optional string tag = 3;
+
+    // Application-supplied ID associated with the notification.
+    optional int32 id = 4;
+
+    // Index of notification in the notification panel.
+    optional int32 shade_index = 5;
+
+    // The number of notifications in the notification panel.
+    optional int32 shade_count = 6;
+
+    // Importance for the notification.
+    optional int32 importance = 7;
+
+    // ID for the notification channel.
+    optional int32 channel_id = 8;
+
+    // Importance for the notification channel.
+    optional int32 channel_importance = 9;
+
+    // Whether notification was a group summary.
+    optional bool group_summary = 10;
+
+    // Time since notification was created in milliseconds.
+    optional int64 since_create_millis = 11;
+
+    // Time since notification was interrupted in milliseconds.
+    optional int64 since_interruption_millis = 12;
+
+    // Time since notification was updated in milliseconds.
+    optional int64 since_update_millis = 13;
+
+    // Time since notification was visible in milliseconds.
+    optional int64 since_visible_millis = 14;
+}
+
+
 //////////////////////////////////////////////////////////////////////
 // Pulled atoms below this line //
 //////////////////////////////////////////////////////////////////////
@@ -2075,6 +2238,11 @@
 
     // SWAP
     optional int64 swap_in_bytes = 8;
+
+    // RSS high watermark.
+    // Peak RSS usage of the process. Value is read from the VmHWM field in /proc/PID/status or
+    // from memory.max_usage_in_bytes under /dev/memcg if the device uses per-app memory cgroups.
+    optional int64 rss_high_watermark_in_bytes = 9;
 }
 
 /*
@@ -2155,6 +2323,16 @@
 }
 
 /**
+ * Pulls battery voltage.
+ * Pulled from:
+ *   frameworks/base/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
+ */
+message BatteryVoltage {
+    // The voltage of the battery, in millivolts.
+    optional int32 voltage_mV = 1;
+}
+
+/**
  * Pulls the temperature of various parts of the device.
  * The units are tenths of a degree Celsius. Eg: 30.3C is reported as 303.
  *
@@ -2175,8 +2353,8 @@
 /**
  * Pulls the statistics of calls to Binder.
  *
- * Binder stats are cumulative from boot unless somebody reset the data using
- * > adb shell dumpsys binder_calls_stats --reset
+ * Binder stats will be reset every time the data is pulled. It means it can only be pulled by one
+ * config on the device.
  *
  * Next tag: 14
  */
@@ -2240,8 +2418,16 @@
     optional int64 exception_count = 2;
 }
 
+/**
+ * Pulls the statistics of message dispatching on HandlerThreads.
+ *
+ * Looper stats will be reset every time the data is pulled. It means it can only be pulled by one
+ * config on the device.
+ *
+ * Next tag: 11
+ */
 message LooperStats {
-    // Currently not collected and always set to 0.
+    // The uid that made a call to the System Server and caused the message to be enqueued.
     optional int32 uid = 1 [(is_uid) = true];
 
     // Fully qualified class name of the handler target class.
@@ -2283,8 +2469,11 @@
     // Total CPU usage of all processed message.
     // Average can be computed using recorded_total_cpu_micros /
     // recorded_message_count. Total can be computed using
-    // recorded_total_cpu_micros / recorded_message_count * call_count.
+    // recorded_total_cpu_micros / recorded_message_count * message_count.
     optional int64 recorded_total_cpu_micros = 9;
+
+    // True if the screen was interactive PowerManager#isInteractive at the end of the call.
+    optional bool screen_interactive = 10;
 }
 
 /**
@@ -2365,3 +2554,23 @@
     // Uses System.currentTimeMillis(), which is wall clock time.
     optional int64 cache_time_millis = 3;
 }
+
+/**
+ * Pulls the number of fingerprints for each user.
+ *
+ * Pulled from StatsCompanionService, which queries FingerprintManager.
+ */
+message NumFingerprints {
+    // The associated user. Eg: 0 for owners, 10+ for others.
+    // Defined in android/os/UserHandle.java
+    optional int32 user = 1;
+    // Number of fingerprints registered to that user.
+    optional int32 num_fingerprints = 2;
+}
+
+/**
+ * Pulled from ProcessStatsService.java
+ */
+message ProcStats {
+    optional android.service.procstats.ProcessStatsSectionProto proc_stats_section = 1;
+}
diff --git a/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp b/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
index ae97d7a..ae2cf74 100644
--- a/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
+++ b/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
@@ -67,6 +67,7 @@
     data->clear();
     bool result_success = true;
 
+    // Get the data from the Health HAL (hardware/interfaces/health/1.0/types.hal).
     Return<void> ret = gHealthHal->getHealthInfo([&](Result r, HealthInfo v) {
         if (r != Result::SUCCESS) {
             result_success = false;
@@ -84,6 +85,12 @@
             ptr->write(v.legacy.batteryFullCharge);
             ptr->init();
             data->push_back(ptr);
+        } else if (mTagId == android::util::BATTERY_VOLTAGE) {
+            auto ptr = make_shared<LogEvent>(android::util::BATTERY_VOLTAGE,
+                wallClockTimestampNs, elapsedTimestampNs);
+            ptr->write(v.legacy.batteryVoltage);
+            ptr->init();
+            data->push_back(ptr);
         } else {
             ALOGE("Unsupported tag in ResourceHealthManagerPuller: %d", mTagId);
         }
diff --git a/cmds/statsd/src/external/StatsCompanionServicePuller.cpp b/cmds/statsd/src/external/StatsCompanionServicePuller.cpp
index d953f50..6d7bba0 100644
--- a/cmds/statsd/src/external/StatsCompanionServicePuller.cpp
+++ b/cmds/statsd/src/external/StatsCompanionServicePuller.cpp
@@ -36,8 +36,6 @@
 namespace os {
 namespace statsd {
 
-const int kLogMsgHeaderSize = 28;
-
 // The reading and parsing are implemented in Java. It is not difficult to port over. But for now
 // let StatsCompanionService handle that and send the data back.
 StatsCompanionServicePuller::StatsCompanionServicePuller(int tagId) : StatsPuller(tagId) {
@@ -56,20 +54,12 @@
         vector<StatsLogEventWrapper> returned_value;
         Status status = statsCompanionServiceCopy->pullData(mTagId, &returned_value);
         if (!status.isOk()) {
-            ALOGW("error pulling for %d", mTagId);
+            ALOGW("StatsCompanionServicePuller::pull failed to pull for %d", mTagId);
             return false;
         }
         data->clear();
-        int32_t timestampSec = getWallClockSec();
         for (const StatsLogEventWrapper& it : returned_value) {
-            log_msg tmp;
-            tmp.entry_v1.len = it.bytes.size();
-            // Manually set the header size to 28 bytes to match the pushed log events.
-            tmp.entry.hdr_size = kLogMsgHeaderSize;
-            tmp.entry_v1.sec = timestampSec;
-            // And set the received bytes starting after the 28 bytes reserved for header.
-            std::copy(it.bytes.begin(), it.bytes.end(), tmp.buf + kLogMsgHeaderSize);
-            data->push_back(make_shared<LogEvent>(tmp));
+            data->push_back(make_shared<LogEvent>(it));
         }
         VLOG("StatsCompanionServicePuller::pull succeeded for %d", mTagId);
         return true;
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index dbc13dc..66392f8 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -161,14 +161,20 @@
           {},
           1 * NS_PER_SEC,
           new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}},
+        // battery_voltage
+        {android::util::BATTERY_VOLTAGE,
+         {{},
+          {},
+          1 * NS_PER_SEC,
+          new ResourceHealthManagerPuller(android::util::BATTERY_VOLTAGE)}},
         // process_memory_state
         {android::util::PROCESS_MEMORY_STATE,
-         {{4, 5, 6, 7, 8},
+         {{4, 5, 6, 7, 8, 9},
           {2, 3},
           1 * NS_PER_SEC,
           new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}},
         // temperature
-        {android::util::TEMPERATURE, {{}, {}, 1, new ResourceThermalManagerPuller()}},
+        {android::util::TEMPERATURE, {{}, {}, 1 * NS_PER_SEC, new ResourceThermalManagerPuller()}},
         // binder_calls
         {android::util::BINDER_CALLS,
          {{4, 5, 6, 8, 12},
@@ -184,33 +190,30 @@
         // looper_stats
         {android::util::LOOPER_STATS,
          {{5, 6, 7, 8, 9},
-          {2, 3, 4},
+          {2, 3, 4, 10},
           1 * NS_PER_SEC,
           new StatsCompanionServicePuller(android::util::LOOPER_STATS)}},
         // Disk Stats
         {android::util::DISK_STATS,
-         {{},
-          {},
-          1 * NS_PER_SEC,
-          new StatsCompanionServicePuller(android::util::DISK_STATS)}},
+         {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::DISK_STATS)}},
         // Directory usage
         {android::util::DIRECTORY_USAGE,
-         {{},
-          {},
-          1 * NS_PER_SEC,
-          new StatsCompanionServicePuller(android::util::DIRECTORY_USAGE)}},
+         {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::DIRECTORY_USAGE)}},
         // Size of app's code, data, and cache
         {android::util::APP_SIZE,
-         {{},
-          {},
-          1 * NS_PER_SEC,
-          new StatsCompanionServicePuller(android::util::APP_SIZE)}},
+         {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::APP_SIZE)}},
         // Size of specific categories of files. Eg. Music.
         {android::util::CATEGORY_SIZE,
          {{},
           {},
           1 * NS_PER_SEC,
           new StatsCompanionServicePuller(android::util::CATEGORY_SIZE)}},
+        // Number of fingerprints registered to each user.
+        {android::util::NUM_FINGERPRINTS,
+         {{},
+          {},
+          1 * NS_PER_SEC,
+          new StatsCompanionServicePuller(android::util::NUM_FINGERPRINTS)}},
         };
 
 StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) {
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index 33f3917..bf0bfec 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -400,36 +400,35 @@
     return string(timeBuffer);
 }
 
-void StatsdStats::dumpStats(FILE* out) const {
+void StatsdStats::dumpStats(int out) const {
     lock_guard<std::mutex> lock(mLock);
     time_t t = mStartTimeSec;
     struct tm* tm = localtime(&t);
     char timeBuffer[80];
     strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%d %I:%M%p\n", tm);
-    fprintf(out, "Stats collection start second: %s\n", timeBuffer);
-    fprintf(out, "%lu Config in icebox: \n", (unsigned long)mIceBox.size());
+    dprintf(out, "Stats collection start second: %s\n", timeBuffer);
+    dprintf(out, "%lu Config in icebox: \n", (unsigned long)mIceBox.size());
     for (const auto& configStats : mIceBox) {
-        fprintf(out,
+        dprintf(out,
                 "Config {%d_%lld}: creation=%d, deletion=%d, reset=%d, #metric=%d, #condition=%d, "
                 "#matcher=%d, #alert=%d,  valid=%d\n",
                 configStats->uid, (long long)configStats->id, configStats->creation_time_sec,
                 configStats->deletion_time_sec, configStats->reset_time_sec,
-                configStats->metric_count,
-                configStats->condition_count, configStats->matcher_count, configStats->alert_count,
-                configStats->is_valid);
+                configStats->metric_count, configStats->condition_count, configStats->matcher_count,
+                configStats->alert_count, configStats->is_valid);
 
         for (const auto& broadcastTime : configStats->broadcast_sent_time_sec) {
-            fprintf(out, "\tbroadcast time: %d\n", broadcastTime);
+            dprintf(out, "\tbroadcast time: %d\n", broadcastTime);
         }
 
         for (const auto& dataDropTime : configStats->data_drop_time_sec) {
-            fprintf(out, "\tdata drop time: %d\n", dataDropTime);
+            dprintf(out, "\tdata drop time: %d\n", dataDropTime);
         }
     }
-    fprintf(out, "%lu Active Configs\n", (unsigned long)mConfigStats.size());
+    dprintf(out, "%lu Active Configs\n", (unsigned long)mConfigStats.size());
     for (auto& pair : mConfigStats) {
         auto& configStats = pair.second;
-        fprintf(out,
+        dprintf(out,
                 "Config {%d-%lld}: creation=%d, deletion=%d, #metric=%d, #condition=%d, "
                 "#matcher=%d, #alert=%d,  valid=%d\n",
                 configStats->uid, (long long)configStats->id, configStats->creation_time_sec,
@@ -437,81 +436,81 @@
                 configStats->condition_count, configStats->matcher_count, configStats->alert_count,
                 configStats->is_valid);
         for (const auto& annotation : configStats->annotations) {
-            fprintf(out, "\tannotation: %lld, %d\n", (long long)annotation.first,
+            dprintf(out, "\tannotation: %lld, %d\n", (long long)annotation.first,
                     annotation.second);
         }
 
         for (const auto& broadcastTime : configStats->broadcast_sent_time_sec) {
-            fprintf(out, "\tbroadcast time: %s(%lld)\n",
-                    buildTimeString(broadcastTime).c_str(), (long long)broadcastTime);
+            dprintf(out, "\tbroadcast time: %s(%lld)\n", buildTimeString(broadcastTime).c_str(),
+                    (long long)broadcastTime);
         }
 
         for (const auto& dataDropTime : configStats->data_drop_time_sec) {
-            fprintf(out, "\tdata drop time: %s(%lld)\n",
-                    buildTimeString(dataDropTime).c_str(), (long long)dataDropTime);
+            dprintf(out, "\tdata drop time: %s(%lld)\n", buildTimeString(dataDropTime).c_str(),
+                    (long long)dataDropTime);
         }
 
         for (const auto& dump : configStats->dump_report_stats) {
-            fprintf(out, "\tdump report time: %s(%lld) bytes: %lld\n",
+            dprintf(out, "\tdump report time: %s(%lld) bytes: %lld\n",
                     buildTimeString(dump.first).c_str(), (long long)dump.first,
                     (long long)dump.second);
         }
 
         for (const auto& stats : pair.second->matcher_stats) {
-            fprintf(out, "matcher %lld matched %d times\n", (long long)stats.first, stats.second);
+            dprintf(out, "matcher %lld matched %d times\n", (long long)stats.first, stats.second);
         }
 
         for (const auto& stats : pair.second->condition_stats) {
-            fprintf(out, "condition %lld max output tuple size %d\n", (long long)stats.first,
+            dprintf(out, "condition %lld max output tuple size %d\n", (long long)stats.first,
                     stats.second);
         }
 
         for (const auto& stats : pair.second->condition_stats) {
-            fprintf(out, "metrics %lld max output tuple size %d\n", (long long)stats.first,
+            dprintf(out, "metrics %lld max output tuple size %d\n", (long long)stats.first,
                     stats.second);
         }
 
         for (const auto& stats : pair.second->alert_stats) {
-            fprintf(out, "alert %lld declared %d times\n", (long long)stats.first, stats.second);
+            dprintf(out, "alert %lld declared %d times\n", (long long)stats.first, stats.second);
         }
     }
-    fprintf(out, "********Disk Usage stats***********\n");
+    dprintf(out, "********Disk Usage stats***********\n");
     StorageManager::printStats(out);
-    fprintf(out, "********Pushed Atom stats***********\n");
+    dprintf(out, "********Pushed Atom stats***********\n");
     const size_t atomCounts = mPushedAtomStats.size();
     for (size_t i = 2; i < atomCounts; i++) {
         if (mPushedAtomStats[i] > 0) {
-            fprintf(out, "Atom %lu->%d\n", (unsigned long)i, mPushedAtomStats[i]);
+            dprintf(out, "Atom %lu->%d\n", (unsigned long)i, mPushedAtomStats[i]);
         }
     }
 
-    fprintf(out, "********Pulled Atom stats***********\n");
+    dprintf(out, "********Pulled Atom stats***********\n");
     for (const auto& pair : mPulledAtomStats) {
-        fprintf(out, "Atom %d->%ld, %ld, %ld\n", (int)pair.first, (long)pair.second.totalPull,
+        dprintf(out, "Atom %d->%ld, %ld, %ld\n", (int)pair.first, (long)pair.second.totalPull,
                 (long)pair.second.totalPullFromCache, (long)pair.second.minPullIntervalSec);
     }
 
     if (mAnomalyAlarmRegisteredStats > 0) {
-        fprintf(out, "********AnomalyAlarmStats stats***********\n");
-        fprintf(out, "Anomaly alarm registrations: %d\n", mAnomalyAlarmRegisteredStats);
+        dprintf(out, "********AnomalyAlarmStats stats***********\n");
+        dprintf(out, "Anomaly alarm registrations: %d\n", mAnomalyAlarmRegisteredStats);
     }
 
     if (mPeriodicAlarmRegisteredStats > 0) {
-        fprintf(out, "********SubscriberAlarmStats stats***********\n");
-        fprintf(out, "Subscriber alarm registrations: %d\n", mPeriodicAlarmRegisteredStats);
+        dprintf(out, "********SubscriberAlarmStats stats***********\n");
+        dprintf(out, "Subscriber alarm registrations: %d\n", mPeriodicAlarmRegisteredStats);
     }
 
-    fprintf(out, "UID map stats: bytes=%d, changes=%d, deleted=%d, changes lost=%d\n",
+    dprintf(out, "UID map stats: bytes=%d, changes=%d, deleted=%d, changes lost=%d\n",
             mUidMapStats.bytes_used, mUidMapStats.changes, mUidMapStats.deleted_apps,
             mUidMapStats.dropped_changes);
 
     for (const auto& restart : mSystemServerRestartSec) {
-        fprintf(out, "System server restarts at %s(%lld)\n",
-            buildTimeString(restart).c_str(), (long long)restart);
+        dprintf(out, "System server restarts at %s(%lld)\n", buildTimeString(restart).c_str(),
+                (long long)restart);
     }
 
     for (const auto& loss : mLogLossStats) {
-        fprintf(out, "Log loss: %lld (wall clock sec) - %d (count)\n", (long long)loss.first,
+        dprintf(out, "Log loss: %lld (wall clock sec) - %d (count)\n", (long long)loss.first,
                 loss.second);
     }
 }
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index b5156da..a8188c8 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -156,7 +156,7 @@
      * Report a config has been removed.
      */
     void noteConfigRemoved(const ConfigKey& key);
-   /**
+    /**
      * Report a config has been reset when ttl expires.
      */
     void noteConfigReset(const ConfigKey& key);
@@ -202,7 +202,6 @@
      */
     void noteMetricDimensionSize(const ConfigKey& key, const int64_t& id, int size);
 
-
     /**
      * Report the max size of output tuple of dimension in condition across dimensions in what.
      *
@@ -272,8 +271,8 @@
     void notePullFromCache(int pullAtomId);
 
     /*
-    * Records when system server restarts.
-    */
+     * Records when system server restarts.
+     */
     void noteSystemServerRestart(int32_t timeSec);
 
     /**
@@ -296,9 +295,9 @@
     void dumpStats(std::vector<uint8_t>* buffer, bool reset);
 
     /**
-     * Output statsd stats in human readable format to [out] file.
+     * Output statsd stats in human readable format to [out] file descriptor.
      */
-    void dumpStats(FILE* out) const;
+    void dumpStats(int outFd) const;
 
     typedef struct {
         long totalPull;
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index cf04ee3..f9f1b38 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -41,6 +41,44 @@
     }
 }
 
+LogEvent::LogEvent(const StatsLogEventWrapper& statsLogEventWrapper) {
+    mTagId = statsLogEventWrapper.getTagId();
+    mLogdTimestampNs = statsLogEventWrapper.getWallClockTimeNs();
+    mElapsedTimestampNs = statsLogEventWrapper.getElapsedRealTimeNs();
+    mLogUid = 0;
+    for (int i = 0; i < (int)statsLogEventWrapper.getElements().size(); i++) {
+        Field field(statsLogEventWrapper.getTagId(), getSimpleField(i + 1));
+        switch (statsLogEventWrapper.getElements()[i].type) {
+            case android::os::StatsLogValue::STATS_LOG_VALUE_TYPE::INT:
+                mValues.push_back(
+                        FieldValue(field, Value(statsLogEventWrapper.getElements()[i].int_value)));
+                break;
+            case android::os::StatsLogValue::STATS_LOG_VALUE_TYPE::LONG:
+                mValues.push_back(
+                        FieldValue(field, Value(statsLogEventWrapper.getElements()[i].long_value)));
+                break;
+            case android::os::StatsLogValue::STATS_LOG_VALUE_TYPE::FLOAT:
+                mValues.push_back(FieldValue(
+                        field, Value(statsLogEventWrapper.getElements()[i].float_value)));
+                break;
+            case android::os::StatsLogValue::STATS_LOG_VALUE_TYPE::DOUBLE:
+                mValues.push_back(FieldValue(
+                        field, Value(statsLogEventWrapper.getElements()[i].double_value)));
+                break;
+            case android::os::StatsLogValue::STATS_LOG_VALUE_TYPE::STRING:
+                mValues.push_back(
+                        FieldValue(field, Value(statsLogEventWrapper.getElements()[i].str_value)));
+                break;
+            case android::os::StatsLogValue::STATS_LOG_VALUE_TYPE::STORAGE:
+                mValues.push_back(FieldValue(
+                        field, Value(statsLogEventWrapper.getElements()[i].storage_value)));
+                break;
+            default:
+                break;
+        }
+    }
+}
+
 LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedTimestampNs) {
     mLogdTimestampNs = wallClockTimestampNs;
     mTagId = tagId;
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 2ee6bdf..9ef0bf4 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -18,6 +18,7 @@
 
 #include "FieldValue.h"
 
+#include <android/os/StatsLogEventWrapper.h>
 #include <android/util/ProtoOutputStream.h>
 #include <log/log_event_list.h>
 #include <log/log_read.h>
@@ -61,6 +62,8 @@
      */
     explicit LogEvent(log_msg& msg);
 
+    explicit LogEvent(const StatsLogEventWrapper& statsLogEventWrapper);
+
     /**
      * Constructs a LogEvent with synthetic data for testing. Must call init() before reading.
      */
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index be94725..4325f0f 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -386,12 +386,12 @@
     StatsdStats::getInstance().setUidMapChanges(mChanges.size());
 }
 
-void UidMap::printUidMap(FILE* out) const {
+void UidMap::printUidMap(int out) const {
     lock_guard<mutex> lock(mMutex);
 
     for (const auto& kv : mMap) {
         if (!kv.second.deleted) {
-            fprintf(out, "%s, v%" PRId64 " (%i)\n", kv.first.second.c_str(), kv.second.versionCode,
+            dprintf(out, "%s, v%" PRId64 " (%i)\n", kv.first.second.c_str(), kv.second.versionCode,
                     kv.first.first);
         }
     }
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index 91f2030..4598369 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -103,7 +103,7 @@
 
     // Helper for debugging contents of this uid map. Can be triggered with:
     // adb shell cmd stats print-uid-map
-    void printUidMap(FILE* out) const;
+    void printUidMap(int outFd) const;
 
     // Commands for indicating to the map that a producer should be notified if an app is updated.
     // This allows the metric producer to distinguish when the same uid or app represents a
diff --git a/cmds/statsd/src/shell/ShellSubscriber.cpp b/cmds/statsd/src/shell/ShellSubscriber.cpp
new file mode 100644
index 0000000..3cd49d7
--- /dev/null
+++ b/cmds/statsd/src/shell/ShellSubscriber.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define DEBUG true  // STOPSHIP if true
+#include "Log.h"
+
+#include "ShellSubscriber.h"
+
+#include "matchers/matcher_util.h"
+
+#include <android-base/file.h>
+
+using android::util::ProtoOutputStream;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+void ShellSubscriber::startNewSubscription(int in, int out, sp<IResultReceiver> resultReceiver) {
+    VLOG("start new shell subscription");
+    {
+        std::lock_guard<std::mutex> lock(mMutex);
+        if (mResultReceiver != nullptr) {
+            VLOG("Only one shell subscriber is allowed.");
+            return;
+        }
+        mInput = in;
+        mOutput = out;
+        mResultReceiver = resultReceiver;
+        IInterface::asBinder(mResultReceiver)->linkToDeath(this);
+    }
+
+    // Spawn another thread to read the config updates from the input file descriptor
+    std::thread reader([in, this] { readConfig(in); });
+    reader.detach();
+
+    std::unique_lock<std::mutex> lk(mMutex);
+
+    mShellDied.wait(lk, [this, resultReceiver] { return mResultReceiver != resultReceiver; });
+    if (reader.joinable()) {
+        reader.join();
+    }
+}
+
+void ShellSubscriber::updateConfig(const ShellSubscription& config) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    mPushedMatchers.clear();
+    for (const auto& pushed : config.pushed()) {
+        mPushedMatchers.push_back(pushed);
+        VLOG("adding matcher for atom %d", pushed.atom_id());
+    }
+}
+
+void ShellSubscriber::readConfig(int in) {
+    if (in <= 0) {
+        return;
+    }
+
+    while (1) {
+        size_t bufferSize = 0;
+        int result = 0;
+        if ((result = read(in, &bufferSize, sizeof(bufferSize))) == 0) {
+            VLOG("Done reading");
+            break;
+        } else if (result < 0 || result != sizeof(bufferSize)) {
+            ALOGE("Error reading config size");
+            break;
+        }
+
+        vector<uint8_t> buffer(bufferSize);
+        if ((result = read(in, buffer.data(), bufferSize)) > 0 && ((size_t)result) == bufferSize) {
+            ShellSubscription config;
+            if (config.ParseFromArray(buffer.data(), bufferSize)) {
+                updateConfig(config);
+            } else {
+                ALOGE("error parsing the config");
+                break;
+            }
+        } else {
+            VLOG("Error reading the config, returned: %d, expecting %zu", result, bufferSize);
+            break;
+        }
+    }
+}
+
+void ShellSubscriber::cleanUpLocked() {
+    // The file descriptors will be closed by binder.
+    mInput = 0;
+    mOutput = 0;
+    mResultReceiver = nullptr;
+    mPushedMatchers.clear();
+    VLOG("done clean up");
+}
+
+void ShellSubscriber::onLogEvent(const LogEvent& event) {
+    std::lock_guard<std::mutex> lock(mMutex);
+
+    if (mOutput <= 0) {
+        return;
+    }
+
+    for (const auto& matcher : mPushedMatchers) {
+        if (matchesSimple(*mUidMap, matcher, event)) {
+            // First write the payload size.
+            size_t bufferSize = mProto.size();
+            write(mOutput, &bufferSize, sizeof(bufferSize));
+
+            // Then write the payload.
+            event.ToProto(mProto);
+            mProto.flush(mOutput);
+            mProto.clear();
+            break;
+        }
+    }
+}
+
+void ShellSubscriber::binderDied(const wp<IBinder>& who) {
+    {
+        VLOG("Shell exits");
+        std::lock_guard<std::mutex> lock(mMutex);
+        cleanUpLocked();
+    }
+    mShellDied.notify_all();
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/shell/ShellSubscriber.h b/cmds/statsd/src/shell/ShellSubscriber.h
new file mode 100644
index 0000000..0ace35f
--- /dev/null
+++ b/cmds/statsd/src/shell/ShellSubscriber.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "logd/LogEvent.h"
+
+#include <android/util/ProtoOutputStream.h>
+#include <binder/IResultReceiver.h>
+#include <condition_variable>
+#include <mutex>
+#include <string>
+#include <thread>
+#include "frameworks/base/cmds/statsd/src/shell/shell_config.pb.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "packages/UidMap.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/**
+ * Handles atoms subscription via shell cmd.
+ *
+ * A shell subscription lasts *until shell exits*. Unlike config based clients, a shell client
+ * communicates with statsd via file descriptors. They can subscribe pushed and pulled atoms.
+ * The atoms are sent back to the client in real time, as opposed to
+ * keeping the data in memory. Shell clients do not subscribe aggregated metrics, as they are
+ * responsible for doing the aggregation after receiving the atom events.
+ *
+ * Shell client pass ShellSubscription in the proto binary format. Client can update the
+ * subscription by sending a new subscription. The new subscription would replace the old one.
+ * Input data stream format is:
+ *
+ * |size_t|subscription proto|size_t|subscription proto|....
+ *
+ * statsd sends the events back in Atom proto binary format. Each Atom message is preceded
+ * with sizeof(size_t) bytes indicating the size of the proto message payload.
+ *
+ * The stream would be in the following format:
+ * |size_t|atom1 proto|size_t|atom2 proto|....
+ *
+ * Only one shell subscriber allowed at a time, because each shell subscriber blocks one thread
+ * until it exits.
+ */
+class ShellSubscriber : public virtual IBinder::DeathRecipient {
+public:
+    ShellSubscriber(sp<UidMap> uidMap) : mUidMap(uidMap){};
+
+    /**
+     * Start a new subscription.
+     */
+    void startNewSubscription(int inFd, int outFd, sp<IResultReceiver> resultReceiver);
+
+    void binderDied(const wp<IBinder>& who);
+
+    void onLogEvent(const LogEvent& event);
+
+private:
+    void readConfig(int in);
+
+    void updateConfig(const ShellSubscription& config);
+
+    void cleanUpLocked();
+
+    sp<UidMap> mUidMap;
+
+    // bool mWritten = false;
+
+    android::util::ProtoOutputStream mProto;
+
+    mutable std::mutex mMutex;
+
+    std::condition_variable mShellDied;  // semaphore for waiting until shell exits.
+
+    int mInput;  // The input file descriptor
+
+    int mOutput;  // The output file descriptor
+
+    sp<IResultReceiver> mResultReceiver;
+
+    std::vector<SimpleAtomMatcher> mPushedMatchers;
+};
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/shell/shell_config.proto b/cmds/statsd/src/shell/shell_config.proto
new file mode 100644
index 0000000..516693d
--- /dev/null
+++ b/cmds/statsd/src/shell/shell_config.proto
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+package android.os.statsd;
+
+option java_package = "com.android.os";
+option java_outer_classname = "ShellConfig";
+
+import "frameworks/base/cmds/statsd/src/statsd_config.proto";
+
+message PulledAtomSubscription {
+    optional int32 atom_id = 1;
+
+    /* gap between two pulls in milliseconds */
+    optional int32 freq_millis = 2;
+}
+
+message ShellSubscription {
+    repeated SimpleAtomMatcher pushed = 1;
+    repeated PulledAtomSubscription pulled = 2;
+}
\ No newline at end of file
diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp
index a0ab3e4..805e583 100644
--- a/cmds/statsd/src/stats_log_util.cpp
+++ b/cmds/statsd/src/stats_log_util.cpp
@@ -322,6 +322,11 @@
                 case STRING:
                     protoOutput->write(FIELD_TYPE_STRING | fieldNum, dim.mValue.str_value);
                     break;
+                case STORAGE:
+                    protoOutput->write(FIELD_TYPE_MESSAGE | fieldNum,
+                                       (const char*)dim.mValue.storage_value.data(),
+                                       dim.mValue.storage_value.size());
+                    break;
                 default:
                     break;
             }
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index 3ebc8a4..2f19a02 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -392,13 +392,13 @@
     }
 }
 
-void StorageManager::printStats(FILE* out) {
-    printDirStats(out, STATS_SERVICE_DIR);
-    printDirStats(out, STATS_DATA_DIR);
+void StorageManager::printStats(int outFd) {
+    printDirStats(outFd, STATS_SERVICE_DIR);
+    printDirStats(outFd, STATS_DATA_DIR);
 }
 
-void StorageManager::printDirStats(FILE* out, const char* path) {
-    fprintf(out, "Printing stats of %s\n", path);
+void StorageManager::printDirStats(int outFd, const char* path) {
+    dprintf(outFd, "Printing stats of %s\n", path);
     unique_ptr<DIR, decltype(&closedir)> dir(opendir(path), closedir);
     if (dir == NULL) {
         VLOG("Path %s does not exist", path);
@@ -418,25 +418,22 @@
         int64_t timestamp = result[0];
         int64_t uid = result[1];
         int64_t configID = result[2];
-        fprintf(out, "\t #%d, Last updated: %lld, UID: %d, Config ID: %lld",
-                fileCount + 1,
-                (long long)timestamp,
-                (int)uid,
-                (long long)configID);
+        dprintf(outFd, "\t #%d, Last updated: %lld, UID: %d, Config ID: %lld", fileCount + 1,
+                (long long)timestamp, (int)uid, (long long)configID);
         string file_name = getFilePath(path, timestamp, uid, configID);
         ifstream file(file_name.c_str(), ifstream::in | ifstream::binary);
         if (file.is_open()) {
             file.seekg(0, ios::end);
             int fileSize = file.tellg();
             file.close();
-            fprintf(out, ", File Size: %d bytes", fileSize);
+            dprintf(outFd, ", File Size: %d bytes", fileSize);
             totalFileSize += fileSize;
         }
-        fprintf(out, "\n");
+        dprintf(outFd, "\n");
         fileCount++;
     }
-    fprintf(out, "\tTotal number of files: %d, Total size of files: %d bytes.\n",
-            fileCount, totalFileSize);
+    dprintf(outFd, "\tTotal number of files: %d, Total size of files: %d bytes.\n", fileCount,
+            totalFileSize);
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/storage/StorageManager.h b/cmds/statsd/src/storage/StorageManager.h
index 4840f3c..8fbc89e 100644
--- a/cmds/statsd/src/storage/StorageManager.h
+++ b/cmds/statsd/src/storage/StorageManager.h
@@ -100,13 +100,13 @@
     /**
      * Prints disk usage statistics related to statsd.
      */
-    static void printStats(FILE* out);
+    static void printStats(int out);
 
 private:
     /**
      * Prints disk usage statistics about a directory related to statsd.
      */
-    static void printDirStats(FILE* out, const char* path);
+    static void printDirStats(int out, const char* path);
 };
 
 }  // namespace statsd
diff --git a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java
index 950a258..455e4bb 100644
--- a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java
+++ b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java
@@ -84,7 +84,8 @@
                     cursor.close();
                 }
                 if (provider != null) {
-                    activityManager.removeContentProviderExternal(providerName, token);
+                    activityManager.removeContentProviderExternalAsUser(providerName, token,
+                            UserHandle.USER_SYSTEM);
                 }
             }
         } catch (RemoteException e) {
diff --git a/config/boot-image-profile.txt b/config/boot-image-profile.txt
index b683138..be9ccec 100644
--- a/config/boot-image-profile.txt
+++ b/config/boot-image-profile.txt
@@ -11067,6 +11067,7 @@
 HPLjava/lang/Long;->valueOf(Ljava/lang/String;I)Ljava/lang/Long;
 HPLjava/lang/Math;->addExact(JJ)J
 HPLjava/lang/Math;->scalb(FI)F
+HPLjava/lang/Object;->wait()V
 HPLjava/lang/StackTraceElement;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V
 HPLjava/lang/String;->copyValueOf([C)Ljava/lang/String;
 HPLjava/lang/String;->join(Ljava/lang/CharSequence;[Ljava/lang/CharSequence;)Ljava/lang/String;
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index a4f13a0..ac16fd3 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -728,8 +728,6 @@
 Landroid/os/Environment;->buildExternalStorageAppObbDirs(Ljava/lang/String;)[Ljava/io/File;
 Landroid/os/Environment;->getDataSystemDirectory()Ljava/io/File;
 Landroid/os/Environment;->getLegacyExternalStorageObbDirectory()Ljava/io/File;
-Landroid/os/Environment;->getOemDirectory()Ljava/io/File;
-Landroid/os/Environment;->getVendorDirectory()Ljava/io/File;
 Landroid/os/Environment;->initForCurrentUser()V
 Landroid/os/Environment;->maybeTranslateEmulatedPathToInternal(Ljava/io/File;)Ljava/io/File;
 Landroid/os/Environment;->sCurrentUser:Landroid/os/Environment$UserEnvironment;
@@ -1001,8 +999,6 @@
 Landroid/os/UserHandle;->AID_CACHE_GID_START:I
 Landroid/os/UserHandle;->AID_ROOT:I
 Landroid/os/UserHandle;->AID_SHARED_GID_START:I
-Landroid/os/UserHandle;->ALL:Landroid/os/UserHandle;
-Landroid/os/UserHandle;->CURRENT:Landroid/os/UserHandle;
 Landroid/os/UserHandle;->CURRENT_OR_SELF:Landroid/os/UserHandle;
 Landroid/os/UserHandle;->ERR_GID:I
 Landroid/os/UserHandle;->formatUid(Ljava/io/PrintWriter;I)V
@@ -2080,27 +2076,20 @@
 Lcom/android/internal/telephony/ISub;->getDefaultSubId()I
 Lcom/android/internal/telephony/ISub;->setDefaultDataSubId(I)V
 Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->endCall()Z
-Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->endCallForSubscriber(I)Z
 Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->getDeviceId(Ljava/lang/String;)Ljava/lang/String;
 Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->isRadioOn(Ljava/lang/String;)Z
 Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->mRemote:Landroid/os/IBinder;
 Lcom/android/internal/telephony/ITelephony$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ITelephony;
 Lcom/android/internal/telephony/ITelephony$Stub;->DESCRIPTOR:Ljava/lang/String;
-Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_answerRingingCall:I
 Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_call:I
 Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_dial:I
-Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_endCall:I
 Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_getDeviceId:I
-Lcom/android/internal/telephony/ITelephony;->answerRingingCall()V
 Lcom/android/internal/telephony/ITelephony;->call(Ljava/lang/String;Ljava/lang/String;)V
 Lcom/android/internal/telephony/ITelephony;->dial(Ljava/lang/String;)V
 Lcom/android/internal/telephony/ITelephony;->disableDataConnectivity()Z
 Lcom/android/internal/telephony/ITelephony;->disableLocationUpdates()V
 Lcom/android/internal/telephony/ITelephony;->enableDataConnectivity()Z
 Lcom/android/internal/telephony/ITelephony;->enableLocationUpdates()V
-Lcom/android/internal/telephony/ITelephony;->endCall()Z
-Lcom/android/internal/telephony/ITelephony;->endCallForSubscriber(I)Z
 Lcom/android/internal/telephony/ITelephony;->getActivePhoneType()I
 Lcom/android/internal/telephony/ITelephony;->getCallState()I
 Lcom/android/internal/telephony/ITelephony;->getDataActivity()I
@@ -2112,12 +2101,8 @@
 Lcom/android/internal/telephony/ITelephony;->hasIccCard()Z
 Lcom/android/internal/telephony/ITelephony;->iccCloseLogicalChannel(II)Z
 Lcom/android/internal/telephony/ITelephony;->iccTransmitApduLogicalChannel(IIIIIIILjava/lang/String;)Ljava/lang/String;
-Lcom/android/internal/telephony/ITelephony;->isIdle(Ljava/lang/String;)Z
-Lcom/android/internal/telephony/ITelephony;->isIdleForSubscriber(ILjava/lang/String;)Z
 Lcom/android/internal/telephony/ITelephony;->isRadioOnForSubscriber(ILjava/lang/String;)Z
-Lcom/android/internal/telephony/ITelephony;->isRinging(Ljava/lang/String;)Z
 Lcom/android/internal/telephony/ITelephony;->setRadio(Z)Z
-Lcom/android/internal/telephony/ITelephony;->silenceRinger()V
 Lcom/android/internal/telephony/ITelephony;->supplyPin(Ljava/lang/String;)Z
 Lcom/android/internal/telephony/ITelephony;->toggleRadioOnOff()V
 Lcom/android/internal/telephony/ITelephony;->updateServiceLocation()V
@@ -2138,6 +2123,7 @@
 Lcom/android/internal/telephony/SmsHeader$ConcatRef;-><init>()V
 Lcom/android/internal/telephony/SmsHeader$PortAddrs;-><init>()V
 Lcom/android/internal/telephony/SmsMessageBase;-><init>()V
+Lcom/android/internal/telephony/uicc/IccUtils;->bytesToHexString([B)Ljava/lang/String;
 Lcom/android/internal/textservice/ITextServicesManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Lcom/android/internal/util/HexDump;->toHexString([BZ)Ljava/lang/String;
 Lcom/android/internal/view/BaseIWindow;-><init>()V
@@ -2226,17 +2212,11 @@
 Lcom/android/org/conscrypt/AbstractConscryptSocket;->setUseSessionTickets(Z)V
 Lcom/android/org/conscrypt/ConscryptFileDescriptorSocket;->setHostname(Ljava/lang/String;)V
 Lcom/android/org/conscrypt/ConscryptFileDescriptorSocket;->setUseSessionTickets(Z)V
-Lcom/android/org/conscrypt/ConscryptSocketBase;->getHostname()Ljava/lang/String;
-Lcom/android/org/conscrypt/ConscryptSocketBase;->getHostnameOrIP()Ljava/lang/String;
-Lcom/android/org/conscrypt/ConscryptSocketBase;->getSoWriteTimeout()I
-Lcom/android/org/conscrypt/ConscryptSocketBase;->setHandshakeTimeout(I)V
-Lcom/android/org/conscrypt/ConscryptSocketBase;->setHostname(Ljava/lang/String;)V
-Lcom/android/org/conscrypt/ConscryptSocketBase;->setSoWriteTimeout(I)V
-Lcom/android/org/conscrypt/ConscryptSocketBase;->socket:Ljava/net/Socket;
 Lcom/android/org/conscrypt/OpenSSLKey;-><init>(J)V
 Lcom/android/org/conscrypt/OpenSSLKey;->fromPrivateKey(Ljava/security/PrivateKey;)Lcom/android/org/conscrypt/OpenSSLKey;
 Lcom/android/org/conscrypt/OpenSSLKey;->getNativeRef()Lcom/android/org/conscrypt/NativeRef$EVP_PKEY;
 Lcom/android/org/conscrypt/OpenSSLKey;->getPublicKey()Ljava/security/PublicKey;
+Lcom/android/org/conscrypt/OpenSSLProvider;-><init>()V
 Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getAlpnSelectedProtocol()[B
 Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getChannelId()[B
 Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getHostname()Ljava/lang/String;
@@ -2258,6 +2238,108 @@
 Lcom/android/org/conscrypt/TrustedCertificateStore;->getCertificateChain(Ljava/security/cert/X509Certificate;)Ljava/util/List;
 Lcom/android/org/conscrypt/TrustManagerImpl;-><init>(Ljava/security/KeyStore;)V
 Lcom/android/org/conscrypt/TrustManagerImpl;->checkServerTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljava/lang/String;)Ljava/util/List;
+Lcom/google/android/mms/ContentType;->getAudioTypes()Ljava/util/ArrayList;
+Lcom/google/android/mms/ContentType;->getImageTypes()Ljava/util/ArrayList;
+Lcom/google/android/mms/ContentType;->getVideoTypes()Ljava/util/ArrayList;
+Lcom/google/android/mms/ContentType;->isAudioType(Ljava/lang/String;)Z
+Lcom/google/android/mms/ContentType;->isDrmType(Ljava/lang/String;)Z
+Lcom/google/android/mms/ContentType;->isImageType(Ljava/lang/String;)Z
+Lcom/google/android/mms/ContentType;->isTextType(Ljava/lang/String;)Z
+Lcom/google/android/mms/ContentType;->isVideoType(Ljava/lang/String;)Z
+Lcom/google/android/mms/MmsException;-><init>()V
+Lcom/google/android/mms/MmsException;-><init>(Ljava/lang/String;)V
+Lcom/google/android/mms/MmsException;-><init>(Ljava/lang/Throwable;)V
+Lcom/google/android/mms/pdu/AcknowledgeInd;-><init>(I[B)V
+Lcom/google/android/mms/pdu/CharacterSets;->getMimeName(I)Ljava/lang/String;
+Lcom/google/android/mms/pdu/DeliveryInd;->getMessageId()[B
+Lcom/google/android/mms/pdu/EncodedStringValue;-><init>(I[B)V
+Lcom/google/android/mms/pdu/EncodedStringValue;-><init>(Ljava/lang/String;)V
+Lcom/google/android/mms/pdu/EncodedStringValue;-><init>([B)V
+Lcom/google/android/mms/pdu/EncodedStringValue;->concat([Lcom/google/android/mms/pdu/EncodedStringValue;)Ljava/lang/String;
+Lcom/google/android/mms/pdu/EncodedStringValue;->encodeStrings([Ljava/lang/String;)[Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/EncodedStringValue;->getString()Ljava/lang/String;
+Lcom/google/android/mms/pdu/GenericPdu;->getMessageType()I
+Lcom/google/android/mms/pdu/GenericPdu;->setFrom(Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getBody()Lcom/google/android/mms/pdu/PduBody;
+Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getDate()J
+Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getPriority()I
+Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getSubject()Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getTo()[Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setBody(Lcom/google/android/mms/pdu/PduBody;)V
+Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setDate(J)V
+Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setPriority(I)V
+Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setSubject(Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/NotificationInd;->getContentLocation()[B
+Lcom/google/android/mms/pdu/NotificationInd;->getExpiry()J
+Lcom/google/android/mms/pdu/NotificationInd;->getFrom()Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/NotificationInd;->getMessageClass()[B
+Lcom/google/android/mms/pdu/NotificationInd;->getMessageSize()J
+Lcom/google/android/mms/pdu/NotificationInd;->getSubject()Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/NotificationInd;->getTransactionId()[B
+Lcom/google/android/mms/pdu/NotificationInd;->setContentLocation([B)V
+Lcom/google/android/mms/pdu/NotifyRespInd;-><init>(I[BI)V
+Lcom/google/android/mms/pdu/PduBody;-><init>()V
+Lcom/google/android/mms/pdu/PduBody;->addPart(ILcom/google/android/mms/pdu/PduPart;)V
+Lcom/google/android/mms/pdu/PduBody;->addPart(Lcom/google/android/mms/pdu/PduPart;)Z
+Lcom/google/android/mms/pdu/PduBody;->getPart(I)Lcom/google/android/mms/pdu/PduPart;
+Lcom/google/android/mms/pdu/PduBody;->getPartByContentId(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart;
+Lcom/google/android/mms/pdu/PduBody;->getPartByContentLocation(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart;
+Lcom/google/android/mms/pdu/PduBody;->getPartByFileName(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart;
+Lcom/google/android/mms/pdu/PduBody;->getPartByName(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart;
+Lcom/google/android/mms/pdu/PduBody;->getPartsNum()I
+Lcom/google/android/mms/pdu/PduComposer;-><init>(Landroid/content/Context;Lcom/google/android/mms/pdu/GenericPdu;)V
+Lcom/google/android/mms/pdu/PduComposer;->make()[B
+Lcom/google/android/mms/pdu/PduParser;->parse()Lcom/google/android/mms/pdu/GenericPdu;
+Lcom/google/android/mms/pdu/PduPart;-><init>()V
+Lcom/google/android/mms/pdu/PduPart;->generateLocation()Ljava/lang/String;
+Lcom/google/android/mms/pdu/PduPart;->getCharset()I
+Lcom/google/android/mms/pdu/PduPart;->getContentLocation()[B
+Lcom/google/android/mms/pdu/PduPart;->getContentType()[B
+Lcom/google/android/mms/pdu/PduPart;->getData()[B
+Lcom/google/android/mms/pdu/PduPart;->getDataUri()Landroid/net/Uri;
+Lcom/google/android/mms/pdu/PduPart;->getFilename()[B
+Lcom/google/android/mms/pdu/PduPart;->getName()[B
+Lcom/google/android/mms/pdu/PduPart;->setCharset(I)V
+Lcom/google/android/mms/pdu/PduPart;->setContentId([B)V
+Lcom/google/android/mms/pdu/PduPart;->setContentLocation([B)V
+Lcom/google/android/mms/pdu/PduPart;->setContentType([B)V
+Lcom/google/android/mms/pdu/PduPart;->setData([B)V
+Lcom/google/android/mms/pdu/PduPart;->setDataUri(Landroid/net/Uri;)V
+Lcom/google/android/mms/pdu/PduPersister;->getBytes(Ljava/lang/String;)[B
+Lcom/google/android/mms/pdu/PduPersister;->getPduPersister(Landroid/content/Context;)Lcom/google/android/mms/pdu/PduPersister;
+Lcom/google/android/mms/pdu/PduPersister;->getPendingMessages(J)Landroid/database/Cursor;
+Lcom/google/android/mms/pdu/PduPersister;->load(Landroid/net/Uri;)Lcom/google/android/mms/pdu/GenericPdu;
+Lcom/google/android/mms/pdu/PduPersister;->move(Landroid/net/Uri;Landroid/net/Uri;)Landroid/net/Uri;
+Lcom/google/android/mms/pdu/PduPersister;->persist(Lcom/google/android/mms/pdu/GenericPdu;Landroid/net/Uri;ZZLjava/util/HashMap;)Landroid/net/Uri;
+Lcom/google/android/mms/pdu/PduPersister;->persistPart(Lcom/google/android/mms/pdu/PduPart;JLjava/util/HashMap;)Landroid/net/Uri;
+Lcom/google/android/mms/pdu/PduPersister;->toIsoString([B)Ljava/lang/String;
+Lcom/google/android/mms/pdu/PduPersister;->updateHeaders(Landroid/net/Uri;Lcom/google/android/mms/pdu/SendReq;)V
+Lcom/google/android/mms/pdu/PduPersister;->updateParts(Landroid/net/Uri;Lcom/google/android/mms/pdu/PduBody;Ljava/util/HashMap;)V
+Lcom/google/android/mms/pdu/ReadOrigInd;->getMessageId()[B
+Lcom/google/android/mms/pdu/ReadRecInd;-><init>(Lcom/google/android/mms/pdu/EncodedStringValue;[BII[Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/ReadRecInd;->setDate(J)V
+Lcom/google/android/mms/pdu/RetrieveConf;->getFrom()Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/RetrieveConf;->getMessageId()[B
+Lcom/google/android/mms/pdu/RetrieveConf;->getTransactionId()[B
+Lcom/google/android/mms/pdu/SendConf;->getMessageId()[B
+Lcom/google/android/mms/pdu/SendConf;->getResponseStatus()I
+Lcom/google/android/mms/pdu/SendConf;->getTransactionId()[B
+Lcom/google/android/mms/pdu/SendReq;-><init>()V
+Lcom/google/android/mms/pdu/SendReq;->getBcc()[Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/SendReq;->getTransactionId()[B
+Lcom/google/android/mms/pdu/SendReq;->setDeliveryReport(I)V
+Lcom/google/android/mms/pdu/SendReq;->setExpiry(J)V
+Lcom/google/android/mms/pdu/SendReq;->setMessageClass([B)V
+Lcom/google/android/mms/pdu/SendReq;->setMessageSize(J)V
+Lcom/google/android/mms/pdu/SendReq;->setReadReport(I)V
+Lcom/google/android/mms/pdu/SendReq;->setTo([Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/util/AbstractCache;->get(Ljava/lang/Object;)Ljava/lang/Object;
+Lcom/google/android/mms/util/PduCache;->getInstance()Lcom/google/android/mms/util/PduCache;
+Lcom/google/android/mms/util/PduCache;->isUpdating(Landroid/net/Uri;)Z
+Lcom/google/android/mms/util/PduCache;->purge(Landroid/net/Uri;)Lcom/google/android/mms/util/PduCacheEntry;
+Lcom/google/android/mms/util/PduCache;->purgeAll()V
+Lcom/google/android/mms/util/PduCacheEntry;->getPdu()Lcom/google/android/mms/pdu/GenericPdu;
+Lcom/google/android/mms/util/SqliteWrapper;->insert(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;Landroid/content/ContentValues;)Landroid/net/Uri;
 Ldalvik/system/BaseDexClassLoader;-><init>(Ljava/lang/String;Ljava/io/File;Ljava/lang/String;Ljava/lang/ClassLoader;Z)V
 Ldalvik/system/BaseDexClassLoader;->addDexPath(Ljava/lang/String;)V
 Ldalvik/system/BaseDexClassLoader;->addDexPath(Ljava/lang/String;Z)V
@@ -2564,6 +2646,7 @@
 Ljava/net/SocketException;-><init>(Ljava/lang/String;Ljava/lang/Throwable;)V
 Ljava/net/SocketImpl;->serverSocket:Ljava/net/ServerSocket;
 Ljava/net/SocketImpl;->socket:Ljava/net/Socket;
+Ljava/net/SocksSocketImpl;-><init>()V
 Ljava/net/URI;->fragment:Ljava/lang/String;
 Ljava/net/URI;->host:Ljava/lang/String;
 Ljava/net/URI;->port:I
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 63c583f..56ca98f 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -1022,6 +1022,7 @@
 android.graphics.-$$Lambda$ColorSpace$Rgb$bWzafC8vMHNuVmRuTUPEFUMlfuY
 android.graphics.-$$Lambda$ColorSpace$S2rlqJvkXGTpUF6mZhvkElds8JE
 android.graphics.BaseCanvas
+android.graphics.BaseRecordingCanvas
 android.graphics.Bitmap
 android.graphics.Bitmap$1
 android.graphics.Bitmap$2
@@ -2381,7 +2382,6 @@
 android.os.-$$Lambda$StrictMode$yZJXPvy2veRNA-xL_SWdXzX_OLg
 android.os.-$$Lambda$Trace$2zLZ-Lc2kAXsVjw_nLYeNhqmGq0
 android.os.AsyncResult
-android.os.AsyncTask
 android.os.AsyncTask$1
 android.os.AsyncTask$2
 android.os.AsyncTask$3
@@ -3304,7 +3304,6 @@
 android.view.OrientationEventListener$SensorEventListenerImpl
 android.view.PointerIcon
 android.view.PointerIcon$1
-android.view.RecordingCanvas
 android.view.RenderNode
 android.view.RenderNode$NoImagePreloadHolder
 android.view.RenderNodeAnimator
diff --git a/config/preloaded-classes-blacklist b/config/preloaded-classes-blacklist
index 8b8d640..eca3bf3 100644
--- a/config/preloaded-classes-blacklist
+++ b/config/preloaded-classes-blacklist
@@ -1,4 +1,5 @@
 android.net.ConnectivityThread$Singleton
+android.os.AsyncTask
 android.os.FileObserver
 android.widget.Magnifier
 sun.nio.fs.UnixChannelFactory
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 446e6cc..f2ad268 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -27,6 +27,7 @@
 import android.content.Intent;
 import android.content.pm.ParceledListSlice;
 import android.graphics.Region;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -73,7 +74,7 @@
  * follows the established service life cycle. Starting an accessibility service is triggered
  * exclusively by the user explicitly turning the service on in device settings. After the system
  * binds to a service, it calls {@link AccessibilityService#onServiceConnected()}. This method can
- * be overriden by clients that want to perform post binding setup.
+ * be overridden by clients that want to perform post binding setup.
  * </p>
  * <p>
  * An accessibility service stops either when the user turns it off in device settings or when
@@ -446,7 +447,7 @@
     @UnsupportedAppUsage
     private AccessibilityServiceInfo mInfo;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private IBinder mWindowToken;
 
     private WindowManager mWindowManager;
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 759443d..aa0275a 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -314,6 +314,12 @@
      */
     public static final int FLAG_REQUEST_FINGERPRINT_GESTURES = 0x00000200;
 
+    /**
+     * This flag requests that accessibility shortcut warning dialog has spoken feedback when
+     * dialog is shown.
+     */
+    public static final int FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK = 0x00000400;
+
     /** {@hide} */
     public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000;
 
@@ -414,6 +420,7 @@
      * @see #FLAG_RETRIEVE_INTERACTIVE_WINDOWS
      * @see #FLAG_ENABLE_ACCESSIBILITY_VOLUME
      * @see #FLAG_REQUEST_ACCESSIBILITY_BUTTON
+     * @see #FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK
      */
     public int flags;
 
@@ -1050,6 +1057,8 @@
                 return "FLAG_REQUEST_ACCESSIBILITY_BUTTON";
             case FLAG_REQUEST_FINGERPRINT_GESTURES:
                 return "FLAG_REQUEST_FINGERPRINT_GESTURES";
+            case FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK:
+                return "FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK";
             default:
                 return null;
         }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 7b86646..2acae1c 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -545,12 +545,12 @@
  * <a name="SavingPersistentState"></a>
  * <h3>Saving Persistent State</h3>
  *
- * <p>There are generally two kinds of persistent state than an activity
+ * <p>There are generally two kinds of persistent state that an activity
  * will deal with: shared document-like data (typically stored in a SQLite
  * database using a {@linkplain android.content.ContentProvider content provider})
  * and internal state such as user preferences.</p>
  *
- * <p>For content provider data, we suggest that activities use a
+ * <p>For content provider data, we suggest that activities use an
  * "edit in place" user model.  That is, any edits a user makes are effectively
  * made immediately without requiring an additional confirmation step.
  * Supporting this model is generally a simple matter of following two rules:</p>
@@ -847,7 +847,7 @@
     /*package*/ ActionBar mActionBar = null;
     private boolean mEnableDefaultActionBarUp;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private VoiceInteractor mVoiceInteractor;
 
     @UnsupportedAppUsage
@@ -1383,6 +1383,7 @@
         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this);
         getApplication().dispatchActivityResumed(this);
         mActivityTransitionState.onResume(this, isTopOfTask());
+        enableAutofillCompatibilityIfNeeded();
         if (mAutoFillResetNeeded) {
             if (!mAutoFillIgnoreFirstResumePause) {
                 View focus = getCurrentFocus();
@@ -1587,11 +1588,13 @@
      * @param outState The bundle to save the state to.
      */
     final void performSaveInstanceState(@NonNull Bundle outState) {
+        getApplication().dispatchActivityPreSaveInstanceState(this, outState);
         onSaveInstanceState(outState);
         saveManagedDialogs(outState);
         mActivityTransitionState.saveState(outState);
         storeHasCurrentPermissionRequest(outState);
         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onSaveInstanceState " + this + ": " + outState);
+        getApplication().dispatchActivityPostSaveInstanceState(this, outState);
     }
 
     /**
@@ -1605,11 +1608,13 @@
      */
     final void performSaveInstanceState(@NonNull Bundle outState,
             @NonNull PersistableBundle outPersistentState) {
+        getApplication().dispatchActivityPreSaveInstanceState(this, outState);
         onSaveInstanceState(outState, outPersistentState);
         saveManagedDialogs(outState);
         storeHasCurrentPermissionRequest(outState);
         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onSaveInstanceState " + this + ": " + outState +
                 ", " + outPersistentState);
+        getApplication().dispatchActivityPostSaveInstanceState(this, outState);
     }
 
     /**
@@ -3523,7 +3528,7 @@
      * {@link android.view.Window#FEATURE_OPTIONS_PANEL} panel,
      * so that subclasses of Activity don't need to deal with feature codes.
      */
-    public boolean onCreatePanelMenu(int featureId, Menu menu) {
+    public boolean onCreatePanelMenu(int featureId, @NonNull Menu menu) {
         if (featureId == Window.FEATURE_OPTIONS_PANEL) {
             boolean show = onCreateOptionsMenu(menu);
             show |= mFragments.dispatchCreateOptionsMenu(menu, getMenuInflater());
@@ -3541,8 +3546,8 @@
      * panel, so that subclasses of
      * Activity don't need to deal with feature codes.
      */
-    public boolean onPreparePanel(int featureId, View view, Menu menu) {
-        if (featureId == Window.FEATURE_OPTIONS_PANEL && menu != null) {
+    public boolean onPreparePanel(int featureId, @Nullable View view, @NonNull Menu menu) {
+        if (featureId == Window.FEATURE_OPTIONS_PANEL) {
             boolean goforit = onPrepareOptionsMenu(menu);
             goforit |= mFragments.dispatchPrepareOptionsMenu(menu);
             return goforit;
@@ -3555,7 +3560,8 @@
      *
      * @return The default implementation returns true.
      */
-    public boolean onMenuOpened(int featureId, Menu menu) {
+    @Override
+    public boolean onMenuOpened(int featureId, @NonNull Menu menu) {
         if (featureId == Window.FEATURE_ACTION_BAR) {
             initWindowDecorActionBar();
             if (mActionBar != null) {
@@ -3576,7 +3582,7 @@
      * panel, so that subclasses of
      * Activity don't need to deal with feature codes.
      */
-    public boolean onMenuItemSelected(int featureId, MenuItem item) {
+    public boolean onMenuItemSelected(int featureId, @NonNull MenuItem item) {
         CharSequence titleCondensed = item.getTitleCondensed();
 
         switch (featureId) {
@@ -3626,7 +3632,7 @@
      * For context menus ({@link Window#FEATURE_CONTEXT_MENU}), the
      * {@link #onContextMenuClosed(Menu)} will be called.
      */
-    public void onPanelClosed(int featureId, Menu menu) {
+    public void onPanelClosed(int featureId, @NonNull Menu menu) {
         switch (featureId) {
             case Window.FEATURE_OPTIONS_PANEL:
                 mFragments.dispatchOptionsMenuClosed(menu);
@@ -3734,7 +3740,7 @@
      *
      * @see #onCreateOptionsMenu
      */
-    public boolean onOptionsItemSelected(MenuItem item) {
+    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
         if (mParent != null) {
             return mParent.onOptionsItemSelected(item);
         }
@@ -3958,7 +3964,7 @@
      * @return boolean Return false to allow normal context menu processing to
      *         proceed, true to consume it here.
      */
-    public boolean onContextItemSelected(MenuItem item) {
+    public boolean onContextItemSelected(@NonNull MenuItem item) {
         if (mParent != null) {
             return mParent.onContextItemSelected(item);
         }
@@ -3972,7 +3978,7 @@
      *
      * @param menu The context menu that is being closed.
      */
-    public void onContextMenuClosed(Menu menu) {
+    public void onContextMenuClosed(@NonNull Menu menu) {
         if (mParent != null) {
             mParent.onContextMenuClosed(menu);
         }
@@ -6385,11 +6391,13 @@
      * closed for you after you return.
      * @param args additional arguments to the dump request.
      */
-    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+    public void dump(@NonNull String prefix, @Nullable FileDescriptor fd,
+            @NonNull PrintWriter writer, @Nullable String[] args) {
         dumpInner(prefix, fd, writer, args);
     }
 
-    void dumpInner(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+    void dumpInner(@NonNull String prefix, @Nullable FileDescriptor fd,
+            @NonNull PrintWriter writer, @Nullable String[] args) {
         if (args != null && args.length > 0 && args[0].equals("--autofill")) {
             dumpAutofillManager(prefix, writer);
             return;
@@ -7097,7 +7105,7 @@
 
     // ------------------ Internal API ------------------
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     final void setParent(Activity parent) {
         mParent = parent;
     }
@@ -7162,7 +7170,6 @@
         mWindow.setColorMode(info.colorMode);
 
         setAutofillCompatibilityEnabled(application.isAutofillCompatibilityEnabled());
-        enableAutofillCompatibilityIfNeeded();
     }
 
     private void enableAutofillCompatibilityIfNeeded() {
@@ -7192,6 +7199,7 @@
 
     @UnsupportedAppUsage
     final void performCreate(Bundle icicle, PersistableBundle persistentState) {
+        getApplication().dispatchActivityPreCreated(this, icicle);
         mCanEnterPictureInPicture = true;
         restoreHasCurrentPermissionRequest(icicle);
         if (persistentState != null) {
@@ -7206,14 +7214,16 @@
                 com.android.internal.R.styleable.Window_windowNoDisplay, false);
         mFragments.dispatchActivityCreated();
         mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
+        getApplication().dispatchActivityPostCreated(this, icicle);
     }
 
-    final void performNewIntent(Intent intent) {
+    final void performNewIntent(@NonNull Intent intent) {
         mCanEnterPictureInPicture = true;
         onNewIntent(intent);
     }
 
     final void performStart(String reason) {
+        getApplication().dispatchActivityPreStarted(this);
         mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
         mFragments.noteStateNotSaved();
         mCalled = false;
@@ -7281,6 +7291,7 @@
         }
 
         mActivityTransitionState.enterReady(this);
+        getApplication().dispatchActivityPostStarted(this);
     }
 
     /**
@@ -7335,6 +7346,7 @@
     }
 
     final void performResume(boolean followedByPause, String reason) {
+        getApplication().dispatchActivityPreResumed(this);
         performRestart(true /* start */, reason);
 
         mFragments.execPendingActions();
@@ -7384,9 +7396,11 @@
                 "Activity " + mComponent.toShortString() +
                 " did not call through to super.onPostResume()");
         }
+        getApplication().dispatchActivityPostResumed(this);
     }
 
     final void performPause() {
+        getApplication().dispatchActivityPrePaused(this);
         mDoReportFullyDrawn = false;
         mFragments.dispatchPause();
         mCalled = false;
@@ -7399,6 +7413,7 @@
                     "Activity " + mComponent.toShortString() +
                     " did not call through to super.onPause()");
         }
+        getApplication().dispatchActivityPostPaused(this);
     }
 
     final void performUserLeaving() {
@@ -7414,6 +7429,7 @@
         mCanEnterPictureInPicture = false;
 
         if (!mStopped) {
+            getApplication().dispatchActivityPreStopped(this);
             if (mWindow != null) {
                 mWindow.closeAllPanels();
             }
@@ -7448,11 +7464,13 @@
             }
 
             mStopped = true;
+            getApplication().dispatchActivityPostStopped(this);
         }
         mResumed = false;
     }
 
     final void performDestroy() {
+        getApplication().dispatchActivityPreDestroyed(this);
         mDestroyed = true;
         mWindow.destroy();
         mFragments.dispatchDestroy();
@@ -7462,6 +7480,7 @@
         if (mVoiceInteractor != null) {
             mVoiceInteractor.detachActivity();
         }
+        getApplication().dispatchActivityPostDestroyed(this);
     }
 
     final void dispatchMultiWindowModeChanged(boolean isInMultiWindowMode,
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 8354235..14b8ae4 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -776,7 +776,7 @@
     /** @hide */
     public int getPackageScreenCompatMode(String packageName) {
         try {
-            return getService().getPackageScreenCompatMode(packageName);
+            return getTaskService().getPackageScreenCompatMode(packageName);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -785,7 +785,7 @@
     /** @hide */
     public void setPackageScreenCompatMode(String packageName, int mode) {
         try {
-            getService().setPackageScreenCompatMode(packageName, mode);
+            getTaskService().setPackageScreenCompatMode(packageName, mode);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -794,7 +794,7 @@
     /** @hide */
     public boolean getPackageAskScreenCompat(String packageName) {
         try {
-            return getService().getPackageAskScreenCompat(packageName);
+            return getTaskService().getPackageAskScreenCompat(packageName);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -803,7 +803,7 @@
     /** @hide */
     public void setPackageAskScreenCompat(String packageName, boolean ask) {
         try {
-            getService().setPackageAskScreenCompat(packageName, ask);
+            getTaskService().setPackageAskScreenCompat(packageName, ask);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1221,7 +1221,7 @@
          * @return The background color.
          * @hide
          */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public int getBackgroundColor() {
             return mColorBackground;
         }
@@ -3379,7 +3379,7 @@
      */
     public ConfigurationInfo getDeviceConfigurationInfo() {
         try {
-            return getService().getDeviceConfigurationInfo();
+            return getTaskService().getDeviceConfigurationInfo();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 87366db..294a3ec 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -18,11 +18,15 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.IIntentReceiver;
 import android.content.IIntentSender;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.UserInfo;
+import android.os.Bundle;
 import android.os.IBinder;
+import android.os.TransactionTooLargeException;
 import android.view.RemoteAnimationAdapter;
 
 import java.util.ArrayList;
@@ -183,12 +187,6 @@
     /** Trims memory usage in the system by removing/stopping unused application processes. */
     public abstract void trimApplications();
 
-    /** Returns the screen compatibility mode for the given application. */
-    public abstract int getPackageScreenCompatMode(ApplicationInfo ai);
-
-    /** Sets the screen compatibility mode for the given application. */
-    public abstract void setPackageScreenCompatMode(ApplicationInfo ai, int mode);
-
     /** Closes all system dialogs. */
     public abstract void closeSystemDialogs(String reason);
 
@@ -201,6 +199,11 @@
     public abstract boolean hasRunningActivity(int uid, @Nullable String packageName);
 
     public abstract void updateOomAdj();
+    public abstract void updateCpuStats();
+    public abstract void updateUsageStats(
+            ComponentName activity, int uid, int userId, boolean resumed);
+    public abstract void updateForegroundTimeIfOnBattery(
+            String packageName, int uid, long cpuTimeDiff);
     public abstract void sendForegroundProfileChanged(int userId);
 
     /**
@@ -226,4 +229,20 @@
 
     /** Gets the task id for a given activity. */
     public abstract int getTaskIdForActivity(@NonNull IBinder token, boolean onlyRoot);
+
+    public abstract void setBooting(boolean booting);
+    public abstract boolean isBooting();
+    public abstract void setBooted(boolean booted);
+    public abstract boolean isBooted();
+    public abstract void finishBooting();
+
+    public abstract void tempWhitelistForPendingIntent(int callerPid, int callerUid, int targetUid,
+            long duration, String tag);
+    public abstract int broadcastIntentInPackage(String packageName, int uid, Intent intent,
+            String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData,
+            Bundle resultExtras, String requiredPermission, Bundle bOptions, boolean serialized,
+            boolean sticky, int userId);
+    public abstract ComponentName startServiceInPackage(int uid, Intent service,
+            String resolvedType, boolean fgRequired, String callingPackage, int userId)
+            throws TransactionTooLargeException;
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 9120701..6754df9 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -340,7 +340,7 @@
     // An executor that performs multi-step transactions.
     private final TransactionExecutor mTransactionExecutor = new TransactionExecutor(this);
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final ResourcesManager mResourcesManager;
 
     private static final class ProviderKey {
@@ -374,7 +374,7 @@
     @UnsupportedAppUsage
     final ArrayMap<IBinder, ProviderRefCount> mProviderRefCountMap
         = new ArrayMap<IBinder, ProviderRefCount>();
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     final ArrayMap<IBinder, ProviderClientRecord> mLocalProviders
         = new ArrayMap<IBinder, ProviderClientRecord>();
     @UnsupportedAppUsage
@@ -394,7 +394,7 @@
     final GcIdler mGcIdler = new GcIdler();
     boolean mGcIdlerScheduled = false;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     static volatile Handler sMainThreadHandler;  // set once in main()
 
     Bundle mCoreSettings = null;
@@ -456,7 +456,7 @@
         private int mLifecycleState = PRE_ON_CREATE;
 
         @VisibleForTesting
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public ActivityClientRecord() {
             this.isForward = false;
             init();
@@ -704,7 +704,7 @@
         @UnsupportedAppUsage
         boolean persistent;
         Configuration config;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         CompatibilityInfo compatInfo;
         String buildSerial;
 
@@ -1541,7 +1541,7 @@
 
         public void scheduleTrimMemory(int level) {
             final Runnable r = PooledLambda.obtainRunnable(ActivityThread::handleTrimMemory,
-                    ActivityThread.this, level);
+                    ActivityThread.this, level).recycleOnUse();
             // Schedule trimming memory after drawing the frame to minimize jank-risk.
             Choreographer choreographer = Choreographer.getMainThreadInstance();
             if (choreographer != null) {
@@ -2088,7 +2088,7 @@
         return mH;
     }
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public final LoadedApk getPackageInfo(String packageName, CompatibilityInfo compatInfo,
             int flags) {
         return getPackageInfo(packageName, compatInfo, flags, UserHandle.myUserId());
@@ -2131,7 +2131,7 @@
             ai = getPackageManager().getApplicationInfo(packageName,
                     PackageManager.GET_SHARED_LIBRARY_FILES
                             | PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
-                    userId);
+                    (userId < 0) ? UserHandle.myUserId() : userId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2177,7 +2177,7 @@
         return getPackageInfo(ai, compatInfo, null, false, true, false);
     }
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public final LoadedApk peekPackageInfo(String packageName, boolean includeCode) {
         synchronized (mResourcesManager) {
             WeakReference<LoadedApk> ref;
@@ -2850,7 +2850,7 @@
         return aInfo;
     }
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public final Activity startActivityNow(Activity parent, String id,
         Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state,
         Activity.NonConfigurationInstances lastNonConfigurationInstances) {
diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java
index dbc8c5d..cf40e06 100644
--- a/core/java/android/app/AlertDialog.java
+++ b/core/java/android/app/AlertDialog.java
@@ -397,7 +397,7 @@
      * @param listener The {@link DialogInterface.OnClickListener} to use.
      * @deprecated Use
      *             {@link #setButton(int, CharSequence, android.content.DialogInterface.OnClickListener)}
-     *             with {@link DialogInterface#BUTTON_POSITIVE}
+     *             with {@link DialogInterface#BUTTON_NEUTRAL}
      */
     @Deprecated
     public void setButton3(CharSequence text, final OnClickListener listener) {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index fd92174..9c47e79 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -429,8 +429,8 @@
     /** @hide */
     @UnsupportedAppUsage
     public static final int OP_BLUETOOTH_SCAN = 77;
-    /** @hide Use the face authentication API. */
-    public static final int OP_USE_FACE = 78;
+    /** @hide Use the BiometricPrompt/BiometricManager APIs. */
+    public static final int OP_USE_BIOMETRIC = 78;
     /** @hide */
     @UnsupportedAppUsage
     public static final int _NUM_OP = 79;
@@ -678,8 +678,8 @@
     /** @hide */
     public static final String OPSTR_BLUETOOTH_SCAN = "android:bluetooth_scan";
 
-    /** @hide Use the face authentication API. */
-    public static final String OPSTR_USE_FACE = "android:use_face";
+    /** @hide Use the BiometricPrompt/BiometricManager APIs. */
+    public static final String OPSTR_USE_BIOMETRIC = "android:use_biometric";
 
     // Warning: If an permission is added here it also has to be added to
     // com.android.packageinstaller.permission.utils.EventLogger
@@ -818,7 +818,7 @@
             OP_MANAGE_IPSEC_TUNNELS,            // MANAGE_IPSEC_HANDOVERS
             OP_START_FOREGROUND,                // START_FOREGROUND
             OP_COARSE_LOCATION,                 // BLUETOOTH_SCAN
-            OP_USE_FACE,                        // FACE
+            OP_USE_BIOMETRIC,                   // BIOMETRIC
     };
 
     /**
@@ -903,7 +903,7 @@
             OPSTR_MANAGE_IPSEC_TUNNELS,
             OPSTR_START_FOREGROUND,
             OPSTR_BLUETOOTH_SCAN,
-            OPSTR_USE_FACE,
+            OPSTR_USE_BIOMETRIC,
     };
 
     /**
@@ -989,7 +989,7 @@
             "MANAGE_IPSEC_TUNNELS",
             "START_FOREGROUND",
             "BLUETOOTH_SCAN",
-            "USE_FACE",
+            "USE_BIOMETRIC",
     };
 
     /**
@@ -1163,7 +1163,7 @@
             null, // MANAGE_IPSEC_TUNNELS
             null, // START_FOREGROUND
             null, // maybe should be UserManager.DISALLOW_SHARE_LOCATION, //BLUETOOTH_SCAN
-            null, // USE_FACE
+            null, // USE_BIOMETRIC
     };
 
     /**
@@ -1249,7 +1249,7 @@
             false, // MANAGE_IPSEC_HANDOVERS
             false, // START_FOREGROUND
             true, // BLUETOOTH_SCAN
-            false, // USE_FACE
+            false, // USE_BIOMETRIC
     };
 
     /**
@@ -1334,7 +1334,7 @@
             AppOpsManager.MODE_ERRORED,  // MANAGE_IPSEC_TUNNELS
             AppOpsManager.MODE_ALLOWED,  // OP_START_FOREGROUND
             AppOpsManager.MODE_ALLOWED,  // OP_BLUETOOTH_SCAN
-            AppOpsManager.MODE_ALLOWED,  // USE_FACE
+            AppOpsManager.MODE_ALLOWED,  // USE_BIOMETRIC
     };
 
     /**
@@ -1423,7 +1423,7 @@
             false, // MANAGE_IPSEC_TUNNELS
             false, // START_FOREGROUND
             false, // BLUETOOTH_SCAN
-            false, // USE_FACE
+            false, // USE_BIOMETRIC
     };
 
     /**
diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java
index 68b745d..e12942f 100644
--- a/core/java/android/app/Application.java
+++ b/core/java/android/app/Application.java
@@ -65,13 +65,144 @@
     public LoadedApk mLoadedApk;
 
     public interface ActivityLifecycleCallbacks {
+
+        /**
+         * Called as the first step of the Activity being created. This is always called before
+         * {@link Activity#onCreate}.
+         */
+        default void onActivityPreCreated(@NonNull Activity activity,
+                @Nullable Bundle savedInstanceState) {
+        }
+
+        /**
+         * Called when the Activity calls {@link Activity#onCreate super.onCreate()}.
+         */
         void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState);
+
+        /**
+         * Called as the last step of the Activity being created. This is always called after
+         * {@link Activity#onCreate}.
+         */
+        default void onActivityPostCreated(@NonNull Activity activity,
+                @Nullable Bundle savedInstanceState) {
+        }
+
+        /**
+         * Called as the first step of the Activity being started. This is always called before
+         * {@link Activity#onStart}.
+         */
+        default void onActivityPreStarted(@NonNull Activity activity) {
+        }
+
+        /**
+         * Called when the Activity calls {@link Activity#onStart super.onStart()}.
+         */
         void onActivityStarted(@NonNull Activity activity);
+
+        /**
+         * Called as the last step of the Activity being started. This is always called after
+         * {@link Activity#onStart}.
+         */
+        default void onActivityPostStarted(@NonNull Activity activity) {
+        }
+
+        /**
+         * Called as the first step of the Activity being resumed. This is always called before
+         * {@link Activity#onResume}.
+         */
+        default void onActivityPreResumed(@NonNull Activity activity) {
+        }
+
+        /**
+         * Called when the Activity calls {@link Activity#onResume super.onResume()}.
+         */
         void onActivityResumed(@NonNull Activity activity);
+
+        /**
+         * Called as the last step of the Activity being resumed. This is always called after
+         * {@link Activity#onResume} and {@link Activity#onPostResume}.
+         */
+        default void onActivityPostResumed(@NonNull Activity activity) {
+        }
+
+        /**
+         * Called as the first step of the Activity being paused. This is always called before
+         * {@link Activity#onPause}.
+         */
+        default void onActivityPrePaused(@NonNull Activity activity) {
+        }
+
+        /**
+         * Called when the Activity calls {@link Activity#onPause super.onPause()}.
+         */
         void onActivityPaused(@NonNull Activity activity);
+
+        /**
+         * Called as the last step of the Activity being paused. This is always called after
+         * {@link Activity#onPause}.
+         */
+        default void onActivityPostPaused(@NonNull Activity activity) {
+        }
+
+        /**
+         * Called as the first step of the Activity being stopped. This is always called before
+         * {@link Activity#onStop}.
+         */
+        default void onActivityPreStopped(@NonNull Activity activity) {
+        }
+
+        /**
+         * Called when the Activity calls {@link Activity#onStop super.onStop()}.
+         */
         void onActivityStopped(@NonNull Activity activity);
+
+        /**
+         * Called as the last step of the Activity being stopped. This is always called after
+         * {@link Activity#onStop}.
+         */
+        default void onActivityPostStopped(@NonNull Activity activity) {
+        }
+
+        /**
+         * Called as the first step of the Activity saving its instance state. This is always
+         * called before {@link Activity#onSaveInstanceState}.
+         */
+        default void onActivityPreSaveInstanceState(@NonNull Activity activity,
+                @NonNull Bundle outState) {
+        }
+
+        /**
+         * Called when the Activity calls
+         * {@link Activity#onSaveInstanceState super.onSaveInstanceState()}.
+         */
         void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState);
+
+        /**
+         * Called as the last step of the Activity saving its instance state. This is always
+         * called after{@link Activity#onSaveInstanceState}.
+         */
+        default void onActivityPostSaveInstanceState(@NonNull Activity activity,
+                @NonNull Bundle outState) {
+        }
+
+        /**
+         * Called as the first step of the Activity being destroyed. This is always called before
+         * {@link Activity#onDestroy}.
+         */
+        default void onActivityPreDestroyed(@NonNull Activity activity) {
+        }
+
+        /**
+         * Called when the Activity calls {@link Activity#onDestroy super.onDestroy()}.
+         */
         void onActivityDestroyed(@NonNull Activity activity);
+
+        /**
+         * Called as the last step of the Activity being destroyed. This is always called after
+         * {@link Activity#onDestroy}.
+         */
+        default void onActivityPostDestroyed(@NonNull Activity activity) {
+        }
     }
 
     /**
@@ -222,6 +353,18 @@
     }
 
     @UnsupportedAppUsage
+        /* package */ void dispatchActivityPreCreated(@NonNull Activity activity,
+            @Nullable Bundle savedInstanceState) {
+        Object[] callbacks = collectActivityLifecycleCallbacks();
+        if (callbacks != null) {
+            for (int i = 0; i < callbacks.length; i++) {
+                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPreCreated(activity,
+                        savedInstanceState);
+            }
+        }
+    }
+
+    @UnsupportedAppUsage
     /* package */ void dispatchActivityCreated(@NonNull Activity activity,
             @Nullable Bundle savedInstanceState) {
         Object[] callbacks = collectActivityLifecycleCallbacks();
@@ -234,6 +377,28 @@
     }
 
     @UnsupportedAppUsage
+        /* package */ void dispatchActivityPostCreated(@NonNull Activity activity,
+            @Nullable Bundle savedInstanceState) {
+        Object[] callbacks = collectActivityLifecycleCallbacks();
+        if (callbacks != null) {
+            for (int i = 0; i < callbacks.length; i++) {
+                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPostCreated(activity,
+                        savedInstanceState);
+            }
+        }
+    }
+
+    @UnsupportedAppUsage
+        /* package */ void dispatchActivityPreStarted(@NonNull Activity activity) {
+        Object[] callbacks = collectActivityLifecycleCallbacks();
+        if (callbacks != null) {
+            for (int i = 0; i < callbacks.length; i++) {
+                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPreStarted(activity);
+            }
+        }
+    }
+
+    @UnsupportedAppUsage
     /* package */ void dispatchActivityStarted(@NonNull Activity activity) {
         Object[] callbacks = collectActivityLifecycleCallbacks();
         if (callbacks != null) {
@@ -244,6 +409,26 @@
     }
 
     @UnsupportedAppUsage
+        /* package */ void dispatchActivityPostStarted(@NonNull Activity activity) {
+        Object[] callbacks = collectActivityLifecycleCallbacks();
+        if (callbacks != null) {
+            for (int i = 0; i < callbacks.length; i++) {
+                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPostStarted(activity);
+            }
+        }
+    }
+
+    @UnsupportedAppUsage
+        /* package */ void dispatchActivityPreResumed(@NonNull Activity activity) {
+        Object[] callbacks = collectActivityLifecycleCallbacks();
+        if (callbacks != null) {
+            for (int i = 0; i < callbacks.length; i++) {
+                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPreResumed(activity);
+            }
+        }
+    }
+
+    @UnsupportedAppUsage
     /* package */ void dispatchActivityResumed(@NonNull Activity activity) {
         Object[] callbacks = collectActivityLifecycleCallbacks();
         if (callbacks != null) {
@@ -254,6 +439,26 @@
     }
 
     @UnsupportedAppUsage
+        /* package */ void dispatchActivityPostResumed(@NonNull Activity activity) {
+        Object[] callbacks = collectActivityLifecycleCallbacks();
+        if (callbacks != null) {
+            for (int i = 0; i < callbacks.length; i++) {
+                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPostResumed(activity);
+            }
+        }
+    }
+
+    @UnsupportedAppUsage
+        /* package */ void dispatchActivityPrePaused(@NonNull Activity activity) {
+        Object[] callbacks = collectActivityLifecycleCallbacks();
+        if (callbacks != null) {
+            for (int i = 0; i < callbacks.length; i++) {
+                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPrePaused(activity);
+            }
+        }
+    }
+
+    @UnsupportedAppUsage
     /* package */ void dispatchActivityPaused(@NonNull Activity activity) {
         Object[] callbacks = collectActivityLifecycleCallbacks();
         if (callbacks != null) {
@@ -264,6 +469,26 @@
     }
 
     @UnsupportedAppUsage
+        /* package */ void dispatchActivityPostPaused(@NonNull Activity activity) {
+        Object[] callbacks = collectActivityLifecycleCallbacks();
+        if (callbacks != null) {
+            for (int i = 0; i < callbacks.length; i++) {
+                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPostPaused(activity);
+            }
+        }
+    }
+
+    @UnsupportedAppUsage
+        /* package */ void dispatchActivityPreStopped(@NonNull Activity activity) {
+        Object[] callbacks = collectActivityLifecycleCallbacks();
+        if (callbacks != null) {
+            for (int i = 0; i < callbacks.length; i++) {
+                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPreStopped(activity);
+            }
+        }
+    }
+
+    @UnsupportedAppUsage
     /* package */ void dispatchActivityStopped(@NonNull Activity activity) {
         Object[] callbacks = collectActivityLifecycleCallbacks();
         if (callbacks != null) {
@@ -274,6 +499,28 @@
     }
 
     @UnsupportedAppUsage
+        /* package */ void dispatchActivityPostStopped(@NonNull Activity activity) {
+        Object[] callbacks = collectActivityLifecycleCallbacks();
+        if (callbacks != null) {
+            for (int i = 0; i < callbacks.length; i++) {
+                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPostStopped(activity);
+            }
+        }
+    }
+
+    @UnsupportedAppUsage
+        /* package */ void dispatchActivityPreSaveInstanceState(@NonNull Activity activity,
+            @NonNull Bundle outState) {
+        Object[] callbacks = collectActivityLifecycleCallbacks();
+        if (callbacks != null) {
+            for (int i = 0; i < callbacks.length; i++) {
+                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPreSaveInstanceState(
+                        activity, outState);
+            }
+        }
+    }
+
+    @UnsupportedAppUsage
     /* package */ void dispatchActivitySaveInstanceState(@NonNull Activity activity,
             @NonNull Bundle outState) {
         Object[] callbacks = collectActivityLifecycleCallbacks();
@@ -286,6 +533,28 @@
     }
 
     @UnsupportedAppUsage
+        /* package */ void dispatchActivityPostSaveInstanceState(@NonNull Activity activity,
+            @NonNull Bundle outState) {
+        Object[] callbacks = collectActivityLifecycleCallbacks();
+        if (callbacks != null) {
+            for (int i = 0; i < callbacks.length; i++) {
+                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPostSaveInstanceState(
+                        activity, outState);
+            }
+        }
+    }
+
+    @UnsupportedAppUsage
+        /* package */ void dispatchActivityPreDestroyed(@NonNull Activity activity) {
+        Object[] callbacks = collectActivityLifecycleCallbacks();
+        if (callbacks != null) {
+            for (int i = 0; i < callbacks.length; i++) {
+                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPreDestroyed(activity);
+            }
+        }
+    }
+
+    @UnsupportedAppUsage
     /* package */ void dispatchActivityDestroyed(@NonNull Activity activity) {
         Object[] callbacks = collectActivityLifecycleCallbacks();
         if (callbacks != null) {
@@ -295,6 +564,16 @@
         }
     }
 
+    @UnsupportedAppUsage
+        /* package */ void dispatchActivityPostDestroyed(@NonNull Activity activity) {
+        Object[] callbacks = collectActivityLifecycleCallbacks();
+        if (callbacks != null) {
+            for (int i = 0; i < callbacks.length; i++) {
+                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPostDestroyed(activity);
+            }
+        }
+    }
+
     private Object[] collectComponentCallbacks() {
         Object[] callbacks = null;
         synchronized (mComponentCallbacks) {
diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java
index cd4ace6..62f6bac 100644
--- a/core/java/android/app/AutomaticZenRule.java
+++ b/core/java/android/app/AutomaticZenRule.java
@@ -16,11 +16,14 @@
 
 package android.app;
 
+import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
+
 import android.app.NotificationManager.InterruptionFilter;
 import android.content.ComponentName;
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.service.notification.ZenPolicy;
 
 import java.util.Objects;
 
@@ -35,6 +38,7 @@
     private Uri conditionId;
     private ComponentName owner;
     private long creationTime;
+    private ZenPolicy mZenPolicy;
 
     /**
      * Creates an automatic zen rule.
@@ -58,7 +62,27 @@
     }
 
     /**
-     * @SystemApi
+     * Creates an automatic zen rule.
+     *
+     * @param name The name of the rule.
+     * @param owner The Condition Provider service that owns this rule.
+     * @param conditionId A representation of the state that should cause the Condition Provider
+     *                    service to apply the given interruption filter.
+     * @param policy The policy defines which notifications are allowed to interrupt the user
+     *               while this rule is active
+     * @param enabled Whether the rule is enabled.
+     */
+    public AutomaticZenRule(String name, ComponentName owner, Uri conditionId, ZenPolicy policy,
+            boolean enabled) {
+        this.name = name;
+        this.owner = owner;
+        this.conditionId = conditionId;
+        this.interruptionFilter = INTERRUPTION_FILTER_PRIORITY;
+        this.enabled = enabled;
+        this.mZenPolicy = policy;
+    }
+
+    /**
      * @hide
      */
     public AutomaticZenRule(String name, ComponentName owner, Uri conditionId,
@@ -67,6 +91,15 @@
         this.creationTime = creationTime;
     }
 
+    /**
+     * @hide
+     */
+    public AutomaticZenRule(String name, ComponentName owner, Uri conditionId, ZenPolicy policy,
+            boolean enabled, long creationTime) {
+        this(name, owner, conditionId, policy, enabled);
+        this.creationTime = creationTime;
+    }
+
     public AutomaticZenRule(Parcel source) {
         enabled = source.readInt() == 1;
         if (source.readInt() == 1) {
@@ -76,6 +109,7 @@
         conditionId = source.readParcelable(null);
         owner = source.readParcelable(null);
         creationTime = source.readLong();
+        mZenPolicy = source.readParcelable(null);
     }
 
     /**
@@ -114,6 +148,13 @@
     }
 
     /**
+     * Gets the zen policy.
+     */
+    public ZenPolicy getZenPolicy() {
+        return this.mZenPolicy.copy();
+    }
+
+    /**
      * Returns the time this rule was created, represented as milliseconds since the epoch.
      */
     public long getCreationTime() {
@@ -149,6 +190,13 @@
         this.enabled = enabled;
     }
 
+    /**
+     * Sets the zen policy.
+     */
+    public void setZenPolicy(ZenPolicy zenPolicy) {
+        this.mZenPolicy = zenPolicy;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -167,6 +215,7 @@
         dest.writeParcelable(conditionId, 0);
         dest.writeParcelable(owner, 0);
         dest.writeLong(creationTime);
+        dest.writeParcelable(mZenPolicy, 0);
     }
 
     @Override
@@ -178,6 +227,7 @@
                 .append(",conditionId=").append(conditionId)
                 .append(",owner=").append(owner)
                 .append(",creationTime=").append(creationTime)
+                .append(",mZenPolicy=").append(mZenPolicy)
                 .append(']').toString();
     }
 
@@ -191,12 +241,14 @@
                 && other.interruptionFilter == interruptionFilter
                 && Objects.equals(other.conditionId, conditionId)
                 && Objects.equals(other.owner, owner)
-                && other.creationTime == creationTime;
+                && other.creationTime == creationTime
+                && Objects.equals(other.mZenPolicy, mZenPolicy);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(enabled, name, interruptionFilter, conditionId, owner, creationTime);
+        return Objects.hash(enabled, name, interruptionFilter, conditionId, owner, creationTime,
+                mZenPolicy);
     }
 
     public static final Parcelable.Creator<AutomaticZenRule> CREATOR
diff --git a/core/java/android/app/ContentProviderHolder.java b/core/java/android/app/ContentProviderHolder.java
index 1098990..2a13c71 100644
--- a/core/java/android/app/ContentProviderHolder.java
+++ b/core/java/android/app/ContentProviderHolder.java
@@ -20,6 +20,7 @@
 import android.content.ContentProviderNative;
 import android.content.IContentProvider;
 import android.content.pm.ProviderInfo;
+import android.os.Build;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -35,7 +36,7 @@
     @UnsupportedAppUsage
     public IContentProvider provider;
     public IBinder connection;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public boolean noReleaseNeeded;
 
     @UnsupportedAppUsage
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index bbaaee8..77f6395 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -164,7 +164,7 @@
      * Map from preference name to generated path.
      */
     @GuardedBy("ContextImpl.class")
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private ArrayMap<String, File> mSharedPrefsPaths;
 
     @UnsupportedAppUsage
@@ -183,7 +183,7 @@
 
     @UnsupportedAppUsage
     private final String mBasePackageName;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final String mOpPackageName;
 
     private final @NonNull ResourcesManager mResourcesManager;
@@ -191,7 +191,7 @@
     private @NonNull Resources mResources;
     private @Nullable Display mDisplay; // may be null if default display
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final int mFlags;
 
     @UnsupportedAppUsage
diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java
index 37a05f0..9d82ffa 100644
--- a/core/java/android/app/DatePickerDialog.java
+++ b/core/java/android/app/DatePickerDialog.java
@@ -239,7 +239,7 @@
          * @param year the selected year
          * @param month the selected month (0-11 for compatibility with
          *              {@link Calendar#MONTH})
-         * @param dayOfMonth th selected day of the month (1-31, depending on
+         * @param dayOfMonth the selected day of the month (1-31, depending on
          *                   month)
          */
         void onDateSet(DatePicker view, int year, int month, int dayOfMonth);
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index b7bac52..6bcfb2e 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -34,6 +34,7 @@
 import android.content.res.ResourceId;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -133,7 +134,7 @@
     private final Handler mHandler = new Handler();
 
     private static final int DISMISS = 0x43;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private static final int CANCEL = 0x44;
     private static final int SHOW = 0x45;
 
@@ -936,8 +937,8 @@
      * @see Activity#onPreparePanel(int, View, Menu)
      */
     @Override
-    public boolean onPreparePanel(int featureId, View view, Menu menu) {
-        if (featureId == Window.FEATURE_OPTIONS_PANEL && menu != null) {
+    public boolean onPreparePanel(int featureId, @Nullable View view, @NonNull Menu menu) {
+        if (featureId == Window.FEATURE_OPTIONS_PANEL) {
             return onPrepareOptionsMenu(menu) && menu.hasVisibleItems();
         }
         return true;
@@ -947,7 +948,7 @@
      * @see Activity#onMenuOpened(int, Menu)
      */
     @Override
-    public boolean onMenuOpened(int featureId, Menu menu) {
+    public boolean onMenuOpened(int featureId, @NonNull Menu menu) {
         if (featureId == Window.FEATURE_ACTION_BAR) {
             mActionBar.dispatchMenuVisibilityChanged(true);
         }
@@ -958,7 +959,7 @@
      * @see Activity#onMenuItemSelected(int, MenuItem)
      */
     @Override
-    public boolean onMenuItemSelected(int featureId, MenuItem item) {
+    public boolean onMenuItemSelected(int featureId, @NonNull MenuItem item) {
         return false;
     }
 
@@ -966,7 +967,7 @@
      * @see Activity#onPanelClosed(int, Menu)
      */
     @Override
-    public void onPanelClosed(int featureId, Menu menu) {
+    public void onPanelClosed(int featureId, @NonNull Menu menu) {
         if (featureId == Window.FEATURE_ACTION_BAR) {
             mActionBar.dispatchMenuVisibilityChanged(false);
         }
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 35999a2..1622c06 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -879,7 +879,7 @@
          * @return this object
          * @hide
          */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public Query orderBy(String column, int direction) {
             if (direction != ORDER_ASCENDING && direction != ORDER_DESCENDING) {
                 throw new IllegalArgumentException("Invalid direction: " + direction);
@@ -1011,7 +1011,7 @@
     }
 
     /** {@hide} */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public void setAccessFilename(boolean accessFilename) {
         mAccessFilename = accessFilename;
     }
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 9f4157f..49917b4 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -264,7 +264,7 @@
  */
 @Deprecated
 public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListener {
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private static final ArrayMap<String, Class<?>> sClassMap =
             new ArrayMap<String, Class<?>>();
 
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 16360b3..519a274 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -208,8 +208,6 @@
     List<ActivityManager.RunningServiceInfo> getServices(int maxNum, int flags);
     // Retrieve running application processes in the system
     List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses();
-    // Get device configuration
-    ConfigurationInfo getDeviceConfigurationInfo();
     IBinder peekService(in Intent service, in String resolvedType, in String callingPackage);
     // Turn on/off profiling in a particular process.
     boolean profileControl(in String process, int userId, boolean start,
@@ -248,10 +246,7 @@
             boolean runGc, in String path, in ParcelFileDescriptor fd,
             in RemoteCallback finishCallback);
     boolean isUserRunning(int userid, int flags);
-    int getPackageScreenCompatMode(in String packageName);
     void setPackageScreenCompatMode(in String packageName, int mode);
-    boolean getPackageAskScreenCompat(in String packageName);
-    void setPackageAskScreenCompat(in String packageName, boolean ask);
     boolean switchUser(int userid);
     boolean removeTask(int taskId);
     void registerProcessObserver(in IProcessObserver observer);
@@ -263,7 +258,9 @@
     void killAllBackgroundProcesses();
     ContentProviderHolder getContentProviderExternal(in String name, int userId,
             in IBinder token, String tag);
+    /** @deprecated - Use {@link #removeContentProviderExternalAsUser} which takes a user ID. */
     void removeContentProviderExternal(in String name, in IBinder token);
+    void removeContentProviderExternalAsUser(in String name, in IBinder token, int userId);
     // Get memory information about the calling process.
     void getMyMemoryState(out ActivityManager.RunningAppProcessInfo outInfo);
     boolean killProcessesBelowForeground(in String reason);
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 46664c6..b7b6352 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -344,6 +344,9 @@
     void notifyPinnedStackAnimationStarted();
     void notifyPinnedStackAnimationEnded();
 
+    // Get device configuration
+    ConfigurationInfo getDeviceConfigurationInfo();
+
     /**
      * Resizes the pinned stack.
      *
@@ -422,4 +425,9 @@
     void resumeAppSwitches();
     void setActivityController(in IActivityController watcher, boolean imAMonkey);
     void setVoiceKeepAwake(in IVoiceInteractionSession session, boolean keepAwake);
+
+    int getPackageScreenCompatMode(in String packageName);
+    void setPackageScreenCompatMode(in String packageName, int mode);
+    boolean getPackageAskScreenCompat(in String packageName);
+    void setPackageAskScreenCompat(in String packageName, boolean ask);
 }
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 4f004d93..357420b 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -112,6 +112,7 @@
 
     ParceledListSlice getActiveNotificationsFromListener(in INotificationListener token, in String[] keys, int trim);
     ParceledListSlice getSnoozedNotificationsFromListener(in INotificationListener token, int trim);
+    void clearRequestedListenerHints(in INotificationListener token);
     void requestHintsFromListener(in INotificationListener token, int hints);
     int getHintsFromListener(in INotificationListener token);
     void requestInterruptionFilterFromListener(in INotificationListener token, int interruptionFilter);
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/events/StoppedDragingEvent.java b/core/java/android/app/ISmsAppService.aidl
similarity index 64%
rename from packages/SystemUI/src/com/android/systemui/stackdivider/events/StoppedDragingEvent.java
rename to core/java/android/app/ISmsAppService.aidl
index c50d6d6..1ac2ec6 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/events/StoppedDragingEvent.java
+++ b/core/java/android/app/ISmsAppService.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2018 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -11,15 +11,13 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
  */
 
-package com.android.systemui.stackdivider.events;
-
-import com.android.systemui.recents.events.EventBus;
+package android.app;
 
 /**
- * Sent when the divider isn't draging anymore.
+ * @hide
  */
-public class StoppedDragingEvent extends EventBus.Event {
+interface ISmsAppService {
 }
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 3085fe5..b720df8 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -29,6 +29,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -415,7 +416,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public boolean isDeviceLocked(int userId) {
         try {
             return mTrustManager.isDeviceLocked(userId);
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index ddd9441..b827d01 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -111,7 +111,7 @@
     private String mDataDir;
     @UnsupportedAppUsage
     private String mLibDir;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private File mDataDirFile;
     private File mDeviceProtectedDataDirFile;
     private File mCredentialProtectedDataDirFile;
@@ -141,7 +141,7 @@
         = new ArrayMap<>();
     private final ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mUnregisteredReceivers
         = new ArrayMap<>();
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
         = new ArrayMap<>();
     private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mUnboundServices
@@ -1358,7 +1358,7 @@
         final IIntentReceiver.Stub mIIntentReceiver;
         @UnsupportedAppUsage
         final BroadcastReceiver mReceiver;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         final Context mContext;
         final Handler mActivityThread;
         final Instrumentation mInstrumentation;
@@ -1605,7 +1605,7 @@
         private final ServiceDispatcher.InnerConnection mIServiceConnection;
         @UnsupportedAppUsage
         private final ServiceConnection mConnection;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         private final Context mContext;
         private final Handler mActivityThread;
         private final ServiceConnectionLeaked mLocation;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 9dca061..81df447 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1417,7 +1417,7 @@
         public static final int SEMANTIC_ACTION_CALL = 10;
 
         private final Bundle mExtras;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         private Icon mIcon;
         private final RemoteInput[] mRemoteInputs;
         private boolean mAllowGeneratedReplies = true;
@@ -3499,7 +3499,7 @@
 
         /**
          * Set the small icon, which will be used to represent the notification in the
-         * status bar and content view (unless overriden there by a
+         * status bar and content view (unless overridden there by a
          * {@link #setLargeIcon(Bitmap) large icon}).
          *
          * @param icon An Icon object to use.
@@ -4440,7 +4440,7 @@
         }
 
         private CharSequence processTextSpans(CharSequence text) {
-            if (hasForegroundColor()) {
+            if (hasForegroundColor() || mInNightMode) {
                 return ContrastColorUtil.clearColorSpans(text);
             }
             return text;
@@ -8253,7 +8253,10 @@
          * <p>For custom display notifications created using {@link #setDisplayIntent},
          * the default is {@link #SIZE_MEDIUM}. All other notifications size automatically based
          * on their content.
+         *
+         * @deprecated Display intents are no longer supported.
          */
+        @Deprecated
         public static final int SIZE_DEFAULT = 0;
 
         /**
@@ -8261,7 +8264,10 @@
          * with an extra small size.
          * <p>This value is only applicable for custom display notifications created using
          * {@link #setDisplayIntent}.
+         *
+         * @deprecated Display intents are no longer supported.
          */
+        @Deprecated
         public static final int SIZE_XSMALL = 1;
 
         /**
@@ -8269,7 +8275,10 @@
          * with a small size.
          * <p>This value is only applicable for custom display notifications created using
          * {@link #setDisplayIntent}.
+         *
+         * @deprecated Display intents are no longer supported.
          */
+        @Deprecated
         public static final int SIZE_SMALL = 2;
 
         /**
@@ -8277,7 +8286,10 @@
          * with a medium size.
          * <p>This value is only applicable for custom display notifications created using
          * {@link #setDisplayIntent}.
+         *
+         * @deprecated Display intents are no longer supported.
          */
+        @Deprecated
         public static final int SIZE_MEDIUM = 3;
 
         /**
@@ -8285,7 +8297,10 @@
          * with a large size.
          * <p>This value is only applicable for custom display notifications created using
          * {@link #setDisplayIntent}.
+         *
+         * @deprecated Display intents are no longer supported.
          */
+        @Deprecated
         public static final int SIZE_LARGE = 4;
 
         /**
@@ -8293,20 +8308,29 @@
          * full screen.
          * <p>This value is only applicable for custom display notifications created using
          * {@link #setDisplayIntent}.
+         *
+         * @deprecated Display intents are no longer supported.
          */
+        @Deprecated
         public static final int SIZE_FULL_SCREEN = 5;
 
         /**
          * Sentinel value for use with {@link #setHintScreenTimeout} to keep the screen on for a
          * short amount of time when this notification is displayed on the screen. This
          * is the default value.
+         *
+         * @deprecated This feature is no longer supported.
          */
+        @Deprecated
         public static final int SCREEN_TIMEOUT_SHORT = 0;
 
         /**
          * Sentinel value for use with {@link #setHintScreenTimeout} to keep the screen on
          * for a longer amount of time when this notification is displayed on the screen.
+         *
+         * @deprecated This feature is no longer supported.
          */
+        @Deprecated
         public static final int SCREEN_TIMEOUT_LONG = -1;
 
         /** Notification extra which contains wearable extensions */
@@ -8556,7 +8580,9 @@
          * @param intent the {@link PendingIntent} for an activity
          * @return this object for method chaining
          * @see android.app.Notification.WearableExtender#getDisplayIntent
+         * @deprecated Display intents are no longer supported.
          */
+        @Deprecated
         public WearableExtender setDisplayIntent(PendingIntent intent) {
             mDisplayIntent = intent;
             return this;
@@ -8565,7 +8591,10 @@
         /**
          * Get the intent to launch inside of an activity view when displaying this
          * notification. This {@code PendingIntent} should be for an activity.
+         *
+         * @deprecated Display intents are no longer supported.
          */
+        @Deprecated
         public PendingIntent getDisplayIntent() {
             return mDisplayIntent;
         }
@@ -8579,7 +8608,9 @@
          * @param page the notification to add as another page
          * @return this object for method chaining
          * @see android.app.Notification.WearableExtender#getPages
+         * @deprecated Multiple content pages are no longer supported.
          */
+        @Deprecated
         public WearableExtender addPage(Notification page) {
             mPages.add(page);
             return this;
@@ -8594,7 +8625,9 @@
          * @param pages a list of notifications
          * @return this object for method chaining
          * @see android.app.Notification.WearableExtender#getPages
+         * @deprecated Multiple content pages are no longer supported.
          */
+        @Deprecated
         public WearableExtender addPages(List<Notification> pages) {
             mPages.addAll(pages);
             return this;
@@ -8604,7 +8637,9 @@
          * Clear all additional pages present on this builder.
          * @return this object for method chaining.
          * @see #addPage
+         * @deprecated Multiple content pages are no longer supported.
          */
+        @Deprecated
         public WearableExtender clearPages() {
             mPages.clear();
             return this;
@@ -8616,7 +8651,9 @@
          * subsequent pages. This field can be used to separate a notification into multiple
          * sections.
          * @return the pages for this notification
+         * @deprecated Multiple content pages are no longer supported.
          */
+        @Deprecated
         public List<Notification> getPages() {
             return mPages;
         }
@@ -8629,7 +8666,9 @@
          * @param background the background bitmap
          * @return this object for method chaining
          * @see android.app.Notification.WearableExtender#getBackground
+         * @deprecated Background images are no longer supported.
          */
+        @Deprecated
         public WearableExtender setBackground(Bitmap background) {
             mBackground = background;
             return this;
@@ -8642,7 +8681,9 @@
          *
          * @return the background image
          * @see android.app.Notification.WearableExtender#setBackground
+         * @deprecated Background images are no longer supported.
          */
+        @Deprecated
         public Bitmap getBackground() {
             return mBackground;
         }
@@ -8688,15 +8729,11 @@
         }
 
         /**
-         * Set an action from this notification's actions to be clickable with the content of
-         * this notification. This action will no longer display separately from the
-         * notification's content.
+         * Set an action from this notification's actions as the primary action. If the action has a
+         * {@link RemoteInput} associated with it, shortcuts to the options for that input are shown
+         * directly on the notification.
          *
-         * <p>For notifications with multiple pages, child pages can also have content actions
-         * set, although the list of available actions comes from the main notification and not
-         * from the child page's notification.
-         *
-         * @param actionIndex The index of the action to hoist onto the current notification page.
+         * @param actionIndex The index of the primary action.
          *                    If wearable actions were added to the main notification, this index
          *                    will apply to that list, otherwise it will apply to the regular
          *                    actions list.
@@ -8707,13 +8744,8 @@
         }
 
         /**
-         * Get the index of the notification action, if any, that was specified as being clickable
-         * with the content of this notification. This action will no longer display separately
-         * from the notification's content.
-         *
-         * <p>For notifications with multiple pages, child pages can also have content actions
-         * set, although the list of available actions comes from the main notification and not
-         * from the child page's notification.
+         * Get the index of the notification action, if any, that was specified as the primary
+         * action.
          *
          * <p>If wearable specific actions were added to the main notification, this index will
          * apply to that list, otherwise it will apply to the regular actions list.
@@ -8938,7 +8970,9 @@
          * qr codes, as well as other simple black-and-white tickets.
          * @param hintAmbientBigPicture {@code true} to enable converstion and ambient.
          * @return this object for method chaining
+         * @deprecated This feature is no longer supported.
          */
+        @Deprecated
         public WearableExtender setHintAmbientBigPicture(boolean hintAmbientBigPicture) {
             setFlag(FLAG_BIG_PICTURE_AMBIENT, hintAmbientBigPicture);
             return this;
@@ -8950,7 +8984,9 @@
          * qr codes, as well as other simple black-and-white tickets.
          * @return {@code true} if it should be displayed in ambient, false otherwise
          * otherwise. The default value is {@code false} if this was never set.
+         * @deprecated This feature is no longer supported.
          */
+        @Deprecated
         public boolean getHintAmbientBigPicture() {
             return (mFlags & FLAG_BIG_PICTURE_AMBIENT) != 0;
         }
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index b96b39d..07a8504 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -841,9 +841,14 @@
             List<ZenModeConfig.ZenRule> rules = service.getZenRules();
             Map<String, AutomaticZenRule> ruleMap = new HashMap<>();
             for (ZenModeConfig.ZenRule rule : rules) {
-                ruleMap.put(rule.id, new AutomaticZenRule(rule.name, rule.component,
-                        rule.conditionId, zenModeToInterruptionFilter(rule.zenMode), rule.enabled,
-                        rule.creationTime));
+                if (rule.zenPolicy == null) {
+                    ruleMap.put(rule.id, new AutomaticZenRule(rule.name, rule.component,
+                            rule.conditionId, zenModeToInterruptionFilter(rule.zenMode),
+                            rule.enabled, rule.creationTime));
+                } else {
+                    ruleMap.put(rule.id, new AutomaticZenRule(rule.name, rule.component,
+                            rule.conditionId, rule.zenPolicy, rule.enabled, rule.creationTime));
+                }
             }
             return ruleMap;
         } catch (RemoteException e) {
@@ -1631,11 +1636,14 @@
         try {
             final ParceledListSlice<StatusBarNotification> parceledList
                     = service.getAppActiveNotifications(pkg, mContext.getUserId());
-            final List<StatusBarNotification> list = parceledList.getList();
-            return list.toArray(new StatusBarNotification[list.size()]);
+            if (parceledList != null) {
+                final List<StatusBarNotification> list = parceledList.getList();
+                return list.toArray(new StatusBarNotification[list.size()]);
+            }
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
+        return new StatusBarNotification[0];
     }
 
     /**
diff --git a/core/java/android/app/ProcessMemoryState.java b/core/java/android/app/ProcessMemoryState.java
index 39db16d..9bfdae0 100644
--- a/core/java/android/app/ProcessMemoryState.java
+++ b/core/java/android/app/ProcessMemoryState.java
@@ -23,19 +23,20 @@
  * The memory stats for a process.
  * {@hide}
  */
-public class ProcessMemoryState implements Parcelable {
-    public int uid;
-    public String processName;
-    public int oomScore;
-    public long pgfault;
-    public long pgmajfault;
-    public long rssInBytes;
-    public long cacheInBytes;
-    public long swapInBytes;
+public final class ProcessMemoryState implements Parcelable {
+    public final int uid;
+    public final String processName;
+    public final int oomScore;
+    public final long pgfault;
+    public final long pgmajfault;
+    public final long rssInBytes;
+    public final long cacheInBytes;
+    public final long swapInBytes;
+    public final long rssHighWatermarkInBytes;
 
     public ProcessMemoryState(int uid, String processName, int oomScore, long pgfault,
                               long pgmajfault, long rssInBytes, long cacheInBytes,
-                              long swapInBytes) {
+                              long swapInBytes, long rssHighWatermarkInBytes) {
         this.uid = uid;
         this.processName = processName;
         this.oomScore = oomScore;
@@ -44,6 +45,7 @@
         this.rssInBytes = rssInBytes;
         this.cacheInBytes = cacheInBytes;
         this.swapInBytes = swapInBytes;
+        this.rssHighWatermarkInBytes = rssHighWatermarkInBytes;
     }
 
     private ProcessMemoryState(Parcel in) {
@@ -55,6 +57,7 @@
         rssInBytes = in.readLong();
         cacheInBytes = in.readLong();
         swapInBytes = in.readLong();
+        rssHighWatermarkInBytes = in.readLong();
     }
 
     public static final Creator<ProcessMemoryState> CREATOR = new Creator<ProcessMemoryState>() {
@@ -84,5 +87,6 @@
         parcel.writeLong(rssInBytes);
         parcel.writeLong(cacheInBytes);
         parcel.writeLong(swapInBytes);
+        parcel.writeLong(rssHighWatermarkInBytes);
     }
 }
diff --git a/core/java/android/app/SmsAppService.java b/core/java/android/app/SmsAppService.java
new file mode 100644
index 0000000..3f2b025
--- /dev/null
+++ b/core/java/android/app/SmsAppService.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * If the default SMS app has a service that extends this class, the system always tries to bind
+ * it so that the process is always running, which allows the app to have a persistent connection
+ * to the server.
+ *
+ * <p>The service must have {@link android.telephony.TelephonyManager#ACTION_SMS_APP_SERVICE}
+ * action in the intent handler, and be protected with
+ * {@link android.Manifest.permission#BIND_SMS_APP_SERVICE}. However the service does not have to
+ * be exported.
+ *
+ * <p>Apps can use
+ * {@link android.content.pm.PackageManager#setComponentEnabledSetting(ComponentName, int, int)}
+ * to disable/enable the service. Apps should use it to disable the service when it no longer needs
+ * to be running.
+ *
+ * <p>When the owner process crashes, the service will be re-bound automatically after a
+ * back-off.
+ *
+ * <p>Note the process may still be killed if the system is under heavy memory pressure, in which
+ * case the process will be re-started later.
+ */
+public class SmsAppService extends Service {
+    private final ISmsAppService mImpl;
+
+    public SmsAppService() {
+        mImpl = new ISmsAppServiceImpl();
+    }
+
+    @Override
+    public final IBinder onBind(Intent intent) {
+        return mImpl.asBinder();
+    }
+
+    private class ISmsAppServiceImpl extends ISmsAppService.Stub {
+    }
+}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 003f364..0044005 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -53,6 +53,8 @@
 import android.hardware.SensorManager;
 import android.hardware.SerialManager;
 import android.hardware.SystemSensorManager;
+import android.hardware.biometrics.BiometricManager;
+import android.hardware.biometrics.IBiometricService;
 import android.hardware.camera2.CameraManager;
 import android.hardware.display.DisplayManager;
 import android.hardware.face.FaceManager;
@@ -132,6 +134,7 @@
 import android.os.Vibrator;
 import android.os.health.SystemHealthManager;
 import android.os.storage.StorageManager;
+import android.permission.PermissionManager;
 import android.print.IPrintManager;
 import android.print.PrintManager;
 import android.service.oemlock.IOemLockService;
@@ -378,7 +381,7 @@
                 new StaticServiceFetcher<InputMethodManager>() {
             @Override
             public InputMethodManager createService() {
-                return InputMethodManager.getInstance();
+                return InputMethodManager.getInstanceInternal();
             }});
 
         registerService(Context.TEXT_SERVICES_MANAGER_SERVICE, TextServicesManager.class,
@@ -818,6 +821,19 @@
                     }
                 });
 
+        registerService(Context.BIOMETRIC_SERVICE, BiometricManager.class,
+                new CachedServiceFetcher<BiometricManager>() {
+                    @Override
+                    public BiometricManager createService(ContextImpl ctx)
+                            throws ServiceNotFoundException {
+                        final IBinder binder =
+                                ServiceManager.getServiceOrThrow(Context.BIOMETRIC_SERVICE);
+                        final IBiometricService service =
+                                IBiometricService.Stub.asInterface(binder);
+                        return new BiometricManager(ctx.getOuterContext(), service);
+                    }
+                });
+
         registerService(Context.TV_INPUT_SERVICE, TvInputManager.class,
                 new CachedServiceFetcher<TvInputManager>() {
             @Override
@@ -1049,6 +1065,13 @@
                             throws ServiceNotFoundException {
                         return new TimeZoneDetector();
                     }});
+
+        registerService(Context.PERMISSION_SERVICE, PermissionManager.class,
+                new CachedServiceFetcher<PermissionManager>() {
+                    @Override
+                    public PermissionManager createService(ContextImpl ctx) {
+                        return new PermissionManager(ctx.getOuterContext());
+                    }});
     }
 
     /**
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index dbb6c3d..5a25f5a 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -29,6 +29,7 @@
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.hardware.display.DisplayManagerGlobal;
+import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
@@ -193,7 +194,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public UiAutomation(Looper looper, IUiAutomationConnection connection) {
         if (looper == null) {
             throw new IllegalArgumentException("Looper cannot be null!");
@@ -210,7 +211,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public void connect() {
         connect(0);
     }
@@ -282,7 +283,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public void disconnect() {
         synchronized (mLock) {
             if (mIsConnecting) {
@@ -1196,10 +1197,9 @@
                     }
                     if (listener != null) {
                         // Calling out only without a lock held.
-                        mLocalCallbackHandler.post(PooledLambda.obtainRunnable(
+                        mLocalCallbackHandler.sendMessage(PooledLambda.obtainMessage(
                                 OnAccessibilityEventListener::onAccessibilityEvent,
-                                listener, AccessibilityEvent.obtain(event))
-                                .recycleOnUse());
+                                listener, AccessibilityEvent.obtain(event)));
                     }
                 }
 
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index 4f172a4..a554882 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -25,7 +25,6 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceManager.ServiceNotFoundException;
-import android.util.Log;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -214,7 +213,7 @@
     }
 
     /**
-     * Sets the night mode.
+     * Sets the system-wide night mode.
      * <p>
      * The mode can be one of:
      * <ul>
@@ -231,6 +230,12 @@
      * are only effective when the {@link Configuration#UI_MODE_TYPE_CAR car}
      * or {@link Configuration#UI_MODE_TYPE_DESK desk} mode is enabled on a
      * device. Starting in API 23, changes to night mode are always effective.
+     * <p>
+     * Changes to night mode take effect globally and will result in a configuration change
+     * (and potentially an Activity lifecycle event) being applied to all running apps.
+     * Developers interested in an app-local implementation of night mode should consider using
+     * {@link android.support.v7.app.AppCompatDelegate#setDefaultNightMode(int)} to manage the
+     * -night qualifier locally.
      *
      * @param mode the night mode to set
      * @see #getNightMode()
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 2a263d6..bebe79e 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -1288,7 +1288,7 @@
      * requires permission {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public int setBitmap(Bitmap fullImage, Rect visibleCropHint,
             boolean allowBackup, @SetWallpaperFlags int which, int userId)
             throws IOException {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index bd7a2dd..fc67c10 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3450,15 +3450,14 @@
      * @param flags Bit mask of additional options: currently supported flags are
      *            {@link #WIPE_EXTERNAL_STORAGE} and {@link #WIPE_RESET_PROTECTION_DATA}.
      * @param reason a string that contains the reason for wiping data, which can be
-     *                          presented to the user.
+     *            presented to the user. If the string is null or empty, user won't be notified.
      * @throws SecurityException if the calling application does not own an active administrator
      *             that uses {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA}
      * @throws IllegalArgumentException if the input reason string is null or empty.
      */
-    public void wipeData(int flags, @NonNull CharSequence reason) {
+    public void wipeData(int flags, CharSequence reason) {
         throwIfParentInstance("wipeData");
-        Preconditions.checkNotNull(reason, "CharSequence is null");
-        wipeDataInternal(flags, reason.toString());
+        wipeDataInternal(flags, reason != null ? reason.toString() : null);
     }
 
     /**
@@ -3469,7 +3468,7 @@
      * @see #wipeData(int, CharSequence)
      * @hide
      */
-    private void wipeDataInternal(int flags, @NonNull String wipeReasonForUser) {
+    private void wipeDataInternal(int flags, String wipeReasonForUser) {
         if (mService != null) {
             try {
                 mService.wipeDataWithReason(flags, wipeReasonForUser);
diff --git a/core/java/android/app/backup/package.html b/core/java/android/app/backup/package.html
index 8b5e3ba..dd6c254 100644
--- a/core/java/android/app/backup/package.html
+++ b/core/java/android/app/backup/package.html
@@ -11,7 +11,7 @@
 
 <p>All backup and restore operations are controlled by the {@link
 android.app.backup.BackupManager}. Each application that would
-like to enable backup and preserve its data on remote strage must implement a
+like to enable backup and preserve its data on remote storage must implement a
 backup agent. A backup agent can be built by extending either {@link android.app.backup.BackupAgent}
 or {@link android.app.backup.BackupAgentHelper}. The {@link
 android.app.backup.BackupAgentHelper} class provides a wrapper around {@link
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index 9baa16f..556ffa24 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -36,6 +36,7 @@
 import android.net.NetworkSpecifier;
 import android.net.Uri;
 import android.os.BaseBundle;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -311,7 +312,7 @@
     private final long initialBackoffMillis;
     private final int backoffPolicy;
     private final int priority;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final int flags;
 
     /**
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 0994332..dbb00eb 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -25,6 +25,7 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.pm.ParceledListSlice;
+import android.os.Build;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.ArrayMap;
@@ -235,7 +236,7 @@
     @UnsupportedAppUsage
     private static final UsageEvents sEmptyResults = new UsageEvents();
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final Context mContext;
     @UnsupportedAppUsage
     private final IUsageStatsManager mService;
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index d21f76d..466b9ce 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -27,6 +27,7 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.os.Binder;
+import android.os.Build;
 import android.os.IBinder;
 import android.os.ParcelUuid;
 import android.os.RemoteException;
@@ -571,7 +572,7 @@
      * @hide
      */
     @RequiresPermission(Manifest.permission.BLUETOOTH)
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public int getPriority(BluetoothDevice device) {
         if (VDBG) log("getPriority(" + device + ")");
         try {
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 4c655b5..654bfaf 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -81,7 +81,8 @@
  * {@link #getBondedDevices()}; start device discovery with
  * {@link #startDiscovery()}; or create a {@link BluetoothServerSocket} to
  * listen for incoming RFComm connection requests with {@link
- * #listenUsingRfcommWithServiceRecord(String, UUID)}; or start a scan for
+ * #listenUsingRfcommWithServiceRecord(String, UUID)}; listen for incoming L2CAP Connection-oriented
+ * Channels (CoC) connection requests with {@link #listenUsingL2capChannel()}; or start a scan for
  * Bluetooth LE devices with {@link #startLeScan(LeScanCallback callback)}.
  * </p>
  * <p>This class is thread safe.</p>
@@ -2967,7 +2968,7 @@
     /**
      * Create a secure L2CAP Connection-oriented Channel (CoC) {@link BluetoothServerSocket} and
      * assign a dynamic protocol/service multiplexer (PSM) value. This socket can be used to listen
-     * for incoming connections.
+     * for incoming connections. The supported Bluetooth transport is LE only.
      * <p>A remote device connecting to this socket will be authenticated and communication on this
      * socket will be encrypted.
      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening
@@ -2977,21 +2978,16 @@
      * closed, Bluetooth is turned off, or the application exits unexpectedly.
      * <p>The mechanism of disclosing the assigned dynamic PSM value to the initiating peer is
      * defined and performed by the application.
-     * <p>Use {@link BluetoothDevice#createL2capCocSocket(int, int)} to connect to this server
+     * <p>Use {@link BluetoothDevice#createL2capChannel(int)} to connect to this server
      * socket from another Android device that is given the PSM value.
      *
-     * @param transport Bluetooth transport to use, must be {@link BluetoothDevice#TRANSPORT_LE}
      * @return an L2CAP CoC BluetoothServerSocket
      * @throws IOException on error, for example Bluetooth not available, or insufficient
      * permissions, or unable to start this CoC
-     * @hide
      */
     @RequiresPermission(Manifest.permission.BLUETOOTH)
-    public BluetoothServerSocket listenUsingL2capCoc(int transport)
+    public BluetoothServerSocket listenUsingL2capChannel()
             throws IOException {
-        if (transport != BluetoothDevice.TRANSPORT_LE) {
-            throw new IllegalArgumentException("Unsupported transport: " + transport);
-        }
         BluetoothServerSocket socket =
                             new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP_LE, true, true,
                                       SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, false, false);
@@ -3005,7 +3001,7 @@
             throw new IOException("Error: Unable to assign PSM value");
         }
         if (DBG) {
-            Log.d(TAG, "listenUsingL2capCoc: set assigned PSM to "
+            Log.d(TAG, "listenUsingL2capChannel: set assigned PSM to "
                     + assignedPsm);
         }
         socket.setChannel(assignedPsm);
@@ -3014,10 +3010,23 @@
     }
 
     /**
+     * TODO: Remove this hidden method once all the SL4A and other tests are updated to use the new
+     * API name, listenUsingL2capChannel.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
+    public BluetoothServerSocket listenUsingL2capCoc(int transport)
+            throws IOException {
+        Log.e(TAG, "listenUsingL2capCoc: PLEASE USE THE OFFICIAL API, listenUsingL2capChannel");
+        return listenUsingL2capChannel();
+    }
+
+    /**
      * Create an insecure L2CAP Connection-oriented Channel (CoC) {@link BluetoothServerSocket} and
-     * assign a dynamic PSM value. This socket can be used to listen for incoming connections.
+     * assign a dynamic PSM value. This socket can be used to listen for incoming connections. The
+     * supported Bluetooth transport is LE only.
      * <p>The link key is not required to be authenticated, i.e the communication may be vulnerable
-     * to man-in-the-middle attacks. Use {@link #listenUsingL2capCoc}, if an encrypted and
+     * to man-in-the-middle attacks. Use {@link #listenUsingL2capChannel}, if an encrypted and
      * authenticated communication channel is desired.
      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening
      * {@link BluetoothServerSocket}.
@@ -3027,21 +3036,16 @@
      * unexpectedly.
      * <p>The mechanism of disclosing the assigned dynamic PSM value to the initiating peer is
      * defined and performed by the application.
-     * <p>Use {@link BluetoothDevice#createInsecureL2capCocSocket(int, int)} to connect to this
-     * server socket from another Android device that is given the PSM value.
+     * <p>Use {@link BluetoothDevice#createInsecureL2capChannel(int)} to connect to this server
+     * socket from another Android device that is given the PSM value.
      *
-     * @param transport Bluetooth transport to use, must be {@link BluetoothDevice#TRANSPORT_LE}
      * @return an L2CAP CoC BluetoothServerSocket
      * @throws IOException on error, for example Bluetooth not available, or insufficient
      * permissions, or unable to start this CoC
-     * @hide
      */
     @RequiresPermission(Manifest.permission.BLUETOOTH)
-    public BluetoothServerSocket listenUsingInsecureL2capCoc(int transport)
+    public BluetoothServerSocket listenUsingInsecureL2capChannel()
             throws IOException {
-        if (transport != BluetoothDevice.TRANSPORT_LE) {
-            throw new IllegalArgumentException("Unsupported transport: " + transport);
-        }
         BluetoothServerSocket socket =
                             new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP_LE, false, false,
                                       SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, false, false);
@@ -3055,11 +3059,24 @@
             throw new IOException("Error: Unable to assign PSM value");
         }
         if (DBG) {
-            Log.d(TAG, "listenUsingInsecureL2capOn: set assigned PSM to "
+            Log.d(TAG, "listenUsingInsecureL2capChannel: set assigned PSM to "
                     + assignedPsm);
         }
         socket.setChannel(assignedPsm);
 
         return socket;
     }
+
+    /**
+     * TODO: Remove this hidden method once all the SL4A and other tests are updated to use the new
+     * API name, listenUsingInsecureL2capChannel.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
+    public BluetoothServerSocket listenUsingInsecureL2capCoc(int transport)
+            throws IOException {
+        Log.e(TAG, "listenUsingInsecureL2capCoc: PLEASE USE THE OFFICIAL API, "
+                    + "listenUsingInsecureL2capChannel");
+        return listenUsingInsecureL2capChannel();
+    }
 }
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 818a749..73e98cd 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1963,8 +1963,8 @@
     /**
      * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can
      * be used to start a secure outgoing connection to the remote device with the same dynamic
-     * protocol/service multiplexer (PSM) value.
-     * <p>This is designed to be used with {@link BluetoothAdapter#listenUsingL2capCoc(int)} for
+     * protocol/service multiplexer (PSM) value. The supported Bluetooth transport is LE only.
+     * <p>This is designed to be used with {@link BluetoothAdapter#listenUsingL2capChannel()} for
      * peer-peer Bluetooth applications.
      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection.
      * <p>Application using this API is responsible for obtaining PSM value from remote device.
@@ -1975,59 +1975,71 @@
      * secure socket connection is not possible, use {#link createInsecureLeL2capCocSocket(int,
      * int)}.
      *
-     * @param transport Bluetooth transport to use, must be {@link #TRANSPORT_LE}
      * @param psm dynamic PSM value from remote device
      * @return a CoC #BluetoothSocket ready for an outgoing connection
      * @throws IOException on error, for example Bluetooth not available, or insufficient
      * permissions
-     * @hide
      */
     @RequiresPermission(Manifest.permission.BLUETOOTH)
-    public BluetoothSocket createL2capCocSocket(int transport, int psm) throws IOException {
+    public BluetoothSocket createL2capChannel(int psm) throws IOException {
         if (!isBluetoothEnabled()) {
-            Log.e(TAG, "createL2capCocSocket: Bluetooth is not enabled");
+            Log.e(TAG, "createL2capChannel: Bluetooth is not enabled");
             throw new IOException();
         }
-        if (transport != BluetoothDevice.TRANSPORT_LE) {
-            throw new IllegalArgumentException("Unsupported transport: " + transport);
-        }
-        if (DBG) Log.d(TAG, "createL2capCocSocket: transport=" + transport + ", psm=" + psm);
+        if (DBG) Log.d(TAG, "createL2capChannel: psm=" + psm);
         return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP_LE, -1, true, true, this, psm,
                 null);
     }
 
     /**
+     * TODO: Remove this hidden method once all the SL4A and other tests are updated to use the new
+     * API name, createL2capChannel.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
+    public BluetoothSocket createL2capCocSocket(int transport, int psm) throws IOException {
+        Log.e(TAG, "createL2capCocSocket: PLEASE USE THE OFFICIAL API, createL2capChannel");
+        return createL2capChannel(psm);
+    }
+
+    /**
      * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can
      * be used to start a secure outgoing connection to the remote device with the same dynamic
-     * protocol/service multiplexer (PSM) value.
-     * <p>This is designed to be used with {@link BluetoothAdapter#listenUsingInsecureL2capCoc(int)}
-     * for peer-peer Bluetooth applications.
+     * protocol/service multiplexer (PSM) value. The supported Bluetooth transport is LE only.
+     * <p>This is designed to be used with {@link
+     * BluetoothAdapter#listenUsingInsecureL2capChannel()} for peer-peer Bluetooth applications.
      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection.
      * <p>Application using this API is responsible for obtaining PSM value from remote device.
      * <p> The communication channel may not have an authenticated link key, i.e. it may be subject
-     * to man-in-the-middle attacks. Use {@link #createL2capCocSocket(int, int)} if an encrypted and
+     * to man-in-the-middle attacks. Use {@link #createL2capChannel(int)} if an encrypted and
      * authenticated communication channel is possible.
      *
-     * @param transport Bluetooth transport to use, must be {@link #TRANSPORT_LE}
      * @param psm dynamic PSM value from remote device
      * @return a CoC #BluetoothSocket ready for an outgoing connection
      * @throws IOException on error, for example Bluetooth not available, or insufficient
      * permissions
+     */
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
+    public BluetoothSocket createInsecureL2capChannel(int psm) throws IOException {
+        if (!isBluetoothEnabled()) {
+            Log.e(TAG, "createInsecureL2capChannel: Bluetooth is not enabled");
+            throw new IOException();
+        }
+        if (DBG) {
+            Log.d(TAG, "createInsecureL2capChannel: psm=" + psm);
+        }
+        return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP_LE, -1, false, false, this, psm,
+                null);
+    }
+
+    /**
+     * TODO: Remove this hidden method once all the SL4A and other tests are updated to use the new
+     * API name, createInsecureL2capChannel.
      * @hide
      */
     @RequiresPermission(Manifest.permission.BLUETOOTH)
     public BluetoothSocket createInsecureL2capCocSocket(int transport, int psm) throws IOException {
-        if (!isBluetoothEnabled()) {
-            Log.e(TAG, "createInsecureL2capCocSocket: Bluetooth is not enabled");
-            throw new IOException();
-        }
-        if (transport != BluetoothDevice.TRANSPORT_LE) {
-            throw new IllegalArgumentException("Unsupported transport: " + transport);
-        }
-        if (DBG) {
-            Log.d(TAG, "createInsecureL2capCocSocket: transport=" + transport + ", psm=" + psm);
-        }
-        return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP_LE, -1, false, false, this, psm,
-                null);
+        Log.e(TAG, "createL2capCocSocket: PLEASE USE THE OFFICIAL API, createInsecureL2capChannel");
+        return createInsecureL2capChannel(psm);
     }
 }
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 78248ef..29d5a1c 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -17,6 +17,7 @@
 package android.bluetooth;
 
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.os.Handler;
 import android.os.ParcelUuid;
 import android.os.RemoteException;
@@ -52,7 +53,7 @@
     private BluetoothDevice mDevice;
     @UnsupportedAppUsage
     private boolean mAutoConnect;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private int mAuthRetryState;
     private int mConnState;
     private final Object mStateLock = new Object();
diff --git a/core/java/android/bluetooth/BluetoothMapClient.java b/core/java/android/bluetooth/BluetoothMapClient.java
index 183be5f..559a59b 100644
--- a/core/java/android/bluetooth/BluetoothMapClient.java
+++ b/core/java/android/bluetooth/BluetoothMapClient.java
@@ -73,6 +73,8 @@
     /** Connection canceled before completion. */
     public static final int RESULT_CANCELED = 2;
 
+    private static final int UPLOADING_FEATURE_BITMASK = 0x08;
+
     private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
             new IBluetoothStateChangeCallback.Stub() {
                 public void onBluetoothStateChange(boolean up) {
@@ -395,6 +397,23 @@
         return false;
     }
 
+    /**
+     * Returns the "Uploading" feature bit value from the SDP record's
+     * MapSupportedFeatures field (see Bluetooth MAP 1.4 spec, page 114).
+     * @param device The Bluetooth device to get this value for.
+     * @return Returns true if the Uploading bit value in SDP record's
+     *         MapSupportedFeatures field is set. False is returned otherwise.
+     */
+    public boolean isUploadingSupported(BluetoothDevice device) {
+        try {
+            return (mService != null && isEnabled() && isValidDevice(device))
+                && ((mService.getSupportedFeatures(device) & UPLOADING_FEATURE_BITMASK) > 0);
+        } catch (RemoteException e) {
+            Log.e(TAG, e.getMessage());
+        }
+        return false;
+    }
+
     private final ServiceConnection mConnection = new ServiceConnection() {
         public void onServiceConnected(ComponentName className, IBinder service) {
             if (DBG) Log.d(TAG, "Proxy object connected");
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index 9777b5c..3c3a01b 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -21,6 +21,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 
 import java.util.List;
 
@@ -86,7 +87,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     int PAN = 5;
 
     /**
diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java
index ba4b5a5..5fc344a 100644
--- a/core/java/android/bluetooth/BluetoothServerSocket.java
+++ b/core/java/android/bluetooth/BluetoothServerSocket.java
@@ -203,12 +203,11 @@
     /**
      * Returns the assigned dynamic protocol/service multiplexer (PSM) value for the listening L2CAP
      * Connection-oriented Channel (CoC) server socket. This server socket must be returned by the
-     * {#link BluetoothAdapter.listenUsingL2capCoc(int)} or {#link
-     * BluetoothAdapter.listenUsingInsecureL2capCoc(int)}. The returned value is undefined if this
+     * {#link BluetoothAdapter.listenUsingL2capChannel()} or {#link
+     * BluetoothAdapter.listenUsingInsecureL2capChannel()}. The returned value is undefined if this
      * method is called on non-L2CAP server sockets.
      *
      * @return the assigned PSM or LE_PSM value depending on transport
-     * @hide
      */
     public int getPsm() {
         return mChannel;
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index 780f896..3a1e2f5 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -667,6 +667,10 @@
      * @return one of {@link #TYPE_RFCOMM}, {@link #TYPE_SCO} or {@link #TYPE_L2CAP}
      */
     public int getConnectionType() {
+        if (mType == TYPE_L2CAP_LE) {
+            // Treat the LE CoC to be the same type as L2CAP.
+            return TYPE_L2CAP;
+        }
         return mType;
     }
 
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index b55fe76..8691ed4 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -21,6 +21,7 @@
 import android.app.ActivityThread;
 import android.app.IActivityManager;
 import android.app.QueuedWork;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -71,22 +72,22 @@
         /** @hide */
         public static final int TYPE_UNREGISTERED = 2;
 
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         final int mType;
         @UnsupportedAppUsage
         final boolean mOrderedHint;
         @UnsupportedAppUsage
         final boolean mInitialStickyHint;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         final IBinder mToken;
         @UnsupportedAppUsage
         final int mSendingUser;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         final int mFlags;
 
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         int mResultCode;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         String mResultData;
         @UnsupportedAppUsage
         Bundle mResultExtras;
@@ -96,7 +97,7 @@
         boolean mFinished;
 
         /** @hide */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public PendingResult(int resultCode, String resultData, Bundle resultExtras, int type,
                 boolean ordered, boolean sticky, IBinder token, int userId, int flags) {
             mResultCode = resultCode;
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 2b7ea66..089cf10 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -25,6 +25,7 @@
 import android.content.res.AssetFileDescriptor;
 import android.graphics.Bitmap;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.StrictMode;
@@ -198,7 +199,7 @@
         final CharSequence mText;
         final String mHtmlText;
         final Intent mIntent;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         Uri mUri;
 
         /** @hide */
diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java
index 3fe17840..8760efe 100644
--- a/core/java/android/content/ClipboardManager.java
+++ b/core/java/android/content/ClipboardManager.java
@@ -95,9 +95,6 @@
      * Sets the current primary clip on the clipboard.  This is the clip that
      * is involved in normal cut and paste operations.
      *
-     * <em>If the application is not the default IME or does not have input focus this will have
-     * no effect.</em>
-     *
      * @param clip The clipped data item to set.
      * @see #getPrimaryClip()
      * @see #clearPrimaryClip()
@@ -115,9 +112,6 @@
     /**
      * Clears any current primary clip on the clipboard.
      *
-     * <em>If the application is not the default IME or does not have input focus this will have
-     * no effect.</em>
-     *
      * @see #setPrimaryClip(ClipData)
      */
     public void clearPrimaryClip() {
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index f5339ef..a64eead 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -37,6 +37,7 @@
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.IBinder;
@@ -50,6 +51,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
@@ -57,6 +60,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Objects;
 
 /**
  * Content providers are one of the primary building blocks of Android applications, providing
@@ -98,6 +102,7 @@
  * <p>For more information about using content providers, read the
  * <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>
  * developer guide.</p>
+ * </div>
  */
 public abstract class ContentProvider implements ComponentCallbacks2 {
 
@@ -163,7 +168,7 @@
      * in the test, which is available via {@link #getPathPermissions()}.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public ContentProvider(
             Context context,
             String readPermission,
@@ -219,7 +224,7 @@
         @Override
         public Cursor query(String callingPkg, Uri uri, @Nullable String[] projection,
                 @Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal) {
-            validateIncomingUri(uri);
+            uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
             if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
                 // The caller has no access to the data, so return an empty cursor with
@@ -267,7 +272,7 @@
         @Override
         public String getType(Uri uri) {
             // getCallingPackage() isn't available in getType(), as the javadoc states.
-            validateIncomingUri(uri);
+            uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
             Trace.traceBegin(TRACE_TAG_DATABASE, "getType");
             try {
@@ -279,7 +284,7 @@
 
         @Override
         public Uri insert(String callingPkg, Uri uri, ContentValues initialValues) {
-            validateIncomingUri(uri);
+            uri = validateIncomingUri(uri);
             int userId = getUserIdFromUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
             if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
@@ -302,7 +307,7 @@
 
         @Override
         public int bulkInsert(String callingPkg, Uri uri, ContentValues[] initialValues) {
-            validateIncomingUri(uri);
+            uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
             if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
                 return 0;
@@ -326,11 +331,12 @@
             for (int i = 0; i < numOperations; i++) {
                 ContentProviderOperation operation = operations.get(i);
                 Uri uri = operation.getUri();
-                validateIncomingUri(uri);
                 userIds[i] = getUserIdFromUri(uri);
-                if (userIds[i] != UserHandle.USER_CURRENT) {
-                    // Removing the user id from the uri.
-                    operation = new ContentProviderOperation(operation, true);
+                uri = validateIncomingUri(uri);
+                uri = maybeGetUriWithoutUserId(uri);
+                // Rebuild operation if we changed the Uri above
+                if (!Objects.equals(operation.getUri(), uri)) {
+                    operation = new ContentProviderOperation(operation, uri);
                     operations.set(i, operation);
                 }
                 if (operation.isReadOperation()) {
@@ -367,7 +373,7 @@
 
         @Override
         public int delete(String callingPkg, Uri uri, String selection, String[] selectionArgs) {
-            validateIncomingUri(uri);
+            uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
             if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
                 return 0;
@@ -385,7 +391,7 @@
         @Override
         public int update(String callingPkg, Uri uri, ContentValues values, String selection,
                 String[] selectionArgs) {
-            validateIncomingUri(uri);
+            uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
             if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
                 return 0;
@@ -404,7 +410,7 @@
         public ParcelFileDescriptor openFile(
                 String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal,
                 IBinder callerToken) throws FileNotFoundException {
-            validateIncomingUri(uri);
+            uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
             enforceFilePermission(callingPkg, uri, mode, callerToken);
             Trace.traceBegin(TRACE_TAG_DATABASE, "openFile");
@@ -422,7 +428,7 @@
         public AssetFileDescriptor openAssetFile(
                 String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
                 throws FileNotFoundException {
-            validateIncomingUri(uri);
+            uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
             enforceFilePermission(callingPkg, uri, mode, null);
             Trace.traceBegin(TRACE_TAG_DATABASE, "openAssetFile");
@@ -453,7 +459,7 @@
         @Override
         public String[] getStreamTypes(Uri uri, String mimeTypeFilter) {
             // getCallingPackage() isn't available in getType(), as the javadoc states.
-            validateIncomingUri(uri);
+            uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
             Trace.traceBegin(TRACE_TAG_DATABASE, "getStreamTypes");
             try {
@@ -467,7 +473,7 @@
         public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType,
                 Bundle opts, ICancellationSignal cancellationSignal) throws FileNotFoundException {
             Bundle.setDefusable(opts, true);
-            validateIncomingUri(uri);
+            uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
             enforceFilePermission(callingPkg, uri, "r", null);
             Trace.traceBegin(TRACE_TAG_DATABASE, "openTypedAssetFile");
@@ -488,7 +494,7 @@
 
         @Override
         public Uri canonicalize(String callingPkg, Uri uri) {
-            validateIncomingUri(uri);
+            uri = validateIncomingUri(uri);
             int userId = getUserIdFromUri(uri);
             uri = getUriWithoutUserId(uri);
             if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
@@ -506,7 +512,7 @@
 
         @Override
         public Uri uncanonicalize(String callingPkg, Uri uri) {
-            validateIncomingUri(uri);
+            uri = validateIncomingUri(uri);
             int userId = getUserIdFromUri(uri);
             uri = getUriWithoutUserId(uri);
             if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
@@ -525,7 +531,7 @@
         @Override
         public boolean refresh(String callingPkg, Uri uri, Bundle args,
                 ICancellationSignal cancellationSignal) throws RemoteException {
-            validateIncomingUri(uri);
+            uri = validateIncomingUri(uri);
             uri = getUriWithoutUserId(uri);
             if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
                 return false;
@@ -1964,7 +1970,7 @@
          */
         if (mContext == null) {
             mContext = context;
-            if (context != null) {
+            if (context != null && mTransport != null) {
                 mTransport.mAppOpsManager = (AppOpsManager) context.getSystemService(
                         Context.APP_OPS_SERVICE);
             }
@@ -2073,7 +2079,8 @@
     }
 
     /** @hide */
-    private void validateIncomingUri(Uri uri) throws SecurityException {
+    @VisibleForTesting
+    public Uri validateIncomingUri(Uri uri) throws SecurityException {
         String auth = uri.getAuthority();
         if (!mSingleUser) {
             int userId = getUserIdFromAuthority(auth, UserHandle.USER_CURRENT);
@@ -2092,6 +2099,15 @@
             }
             throw new SecurityException(message);
         }
+
+        // Normalize the path by removing any empty path segments, which can be
+        // a source of security issues.
+        final String encodedPath = uri.getEncodedPath();
+        if (encodedPath != null && encodedPath.indexOf("//") != -1) {
+            return uri.buildUpon().encodedPath(encodedPath.replaceAll("//+", "/")).build();
+        } else {
+            return uri;
+        }
     }
 
     /** @hide */
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index 04be572..d315f49 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -24,6 +24,7 @@
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.DeadObjectException;
@@ -73,7 +74,7 @@
     private final ContentResolver mContentResolver;
     @UnsupportedAppUsage
     private final IContentProvider mContentProvider;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final String mPackageName;
     private final boolean mStable;
 
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
index e3d9b19..7dc4577 100644
--- a/core/java/android/content/ContentProviderOperation.java
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -101,13 +101,9 @@
     }
 
     /** @hide */
-    public ContentProviderOperation(ContentProviderOperation cpo, boolean removeUserIdFromUri) {
+    public ContentProviderOperation(ContentProviderOperation cpo, Uri withUri) {
         mType = cpo.mType;
-        if (removeUserIdFromUri) {
-            mUri = ContentProvider.getUriWithoutUserId(cpo.mUri);
-        } else {
-            mUri = cpo.mUri;
-        }
+        mUri = withUri;
         mValues = cpo.mValues;
         mSelection = cpo.mSelection;
         mSelectionArgs = cpo.mSelectionArgs;
@@ -117,14 +113,6 @@
         mYieldAllowed = cpo.mYieldAllowed;
     }
 
-    /** @hide */
-    public ContentProviderOperation getWithoutUserIdInUri() {
-        if (ContentProvider.uriHasUserId(mUri)) {
-            return new ContentProviderOperation(this, true);
-        }
-        return this;
-    }
-
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mType);
         Uri.writeToParcel(dest, mUri);
diff --git a/core/java/android/content/ContentUris.java b/core/java/android/content/ContentUris.java
index dbe8a7c..fd7b372 100644
--- a/core/java/android/content/ContentUris.java
+++ b/core/java/android/content/ContentUris.java
@@ -18,6 +18,8 @@
 
 import android.net.Uri;
 
+import java.util.List;
+
 /**
 * Utility methods useful for working with {@link android.net.Uri} objects
 * that use the &quot;content&quot; (content://) scheme.
@@ -109,4 +111,30 @@
     public static Uri withAppendedId(Uri contentUri, long id) {
         return appendId(contentUri.buildUpon(), id).build();
     }
+
+    /**
+     * Removes any ID from the end of the path.
+     *
+     * @param contentUri that ends with an ID
+     * @return a new URI with the ID removed from the end of the path
+     * @throws IllegalArgumentException when the given URI has no ID to remove
+     *             from the end of the path
+     */
+    public static Uri removeId(Uri contentUri) {
+        // Verify that we have a valid ID to actually remove
+        final String last = contentUri.getLastPathSegment();
+        if (last == null) {
+            throw new IllegalArgumentException("No path segments to remove");
+        } else {
+            Long.parseLong(last);
+        }
+
+        final List<String> segments = contentUri.getPathSegments();
+        final Uri.Builder builder = contentUri.buildUpon();
+        builder.path(null);
+        for (int i = 0; i < segments.size() - 1; i++) {
+            builder.appendPath(segments.get(i));
+        }
+        return builder.build();
+    }
 }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index ddd12a5..d711574 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -327,6 +327,15 @@
     public static final int BIND_ADJUST_WITH_ACTIVITY = 0x0080;
 
     /**
+     * Flag for {@link #bindService}: If binding from something better than perceptible,
+     * still set the adjust below perceptible. This would be used for bound services that can
+     * afford to be evicted when under extreme memory pressure, but should be restarted as soon
+     * as possible.
+     * @hide
+     */
+    public static final int BIND_ADJUST_BELOW_PERCEPTIBLE = 0x0100;
+
+    /**
      * @hide Flag for {@link #bindService}: allows binding to a service provided
      * by an instant app. Note that the caller may not have access to the instant
      * app providing the service which is a violation of the instant app sandbox.
@@ -3022,6 +3031,7 @@
             AUDIO_SERVICE,
             FINGERPRINT_SERVICE,
             //@hide: FACE_SERVICE,
+            BIOMETRIC_SERVICE,
             MEDIA_ROUTER_SERVICE,
             TELEPHONY_SERVICE,
             TELEPHONY_SUBSCRIPTION_SERVICE,
@@ -3078,6 +3088,7 @@
             //@hide: SYSTEM_UPDATE_SERVICE,
             //@hide: TIME_DETECTOR_SERVICE,
             //@hide: TIME_ZONE_DETECTOR_SERVICE,
+            PERMISSION_SERVICE,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ServiceName {}
@@ -3158,11 +3169,11 @@
      *
      * <p>Note: Instant apps, for which {@link PackageManager#isInstantApp()} returns true,
      * don't have access to the following system services: {@link #DEVICE_POLICY_SERVICE},
-     * {@link #FINGERPRINT_SERVICE}, {@link #SHORTCUT_SERVICE}, {@link #USB_SERVICE},
-     * {@link #WALLPAPER_SERVICE}, {@link #WIFI_P2P_SERVICE}, {@link #WIFI_SERVICE},
-     * {@link #WIFI_AWARE_SERVICE}. For these services this method will return <code>null</code>.
-     * Generally, if you are running as an instant app you should always check whether the result
-     * of this method is null.
+     * {@link #FINGERPRINT_SERVICE}, {@link #KEYGUARD_SERVICE}, {@link #SHORTCUT_SERVICE},
+     * {@link #USB_SERVICE}, {@link #WALLPAPER_SERVICE}, {@link #WIFI_P2P_SERVICE},
+     * {@link #WIFI_SERVICE}, {@link #WIFI_AWARE_SERVICE}. For these services this method will
+     * return <code>null</code>.  Generally, if you are running as an instant app you should always
+     * check whether the result of this method is null.
      *
      * @param name The name of the desired service.
      *
@@ -3249,11 +3260,11 @@
      *
      * <p>Note: Instant apps, for which {@link PackageManager#isInstantApp()} returns true,
      * don't have access to the following system services: {@link #DEVICE_POLICY_SERVICE},
-     * {@link #FINGERPRINT_SERVICE}, {@link #SHORTCUT_SERVICE}, {@link #USB_SERVICE},
-     * {@link #WALLPAPER_SERVICE}, {@link #WIFI_P2P_SERVICE}, {@link #WIFI_SERVICE},
-     * {@link #WIFI_AWARE_SERVICE}. For these services this method will return <code>null</code>.
-     * Generally, if you are running as an instant app you should always check whether the result
-     * of this method is null.
+     * {@link #FINGERPRINT_SERVICE}, {@link #KEYGUARD_SERVICE}, {@link #SHORTCUT_SERVICE},
+     * {@link #USB_SERVICE}, {@link #WALLPAPER_SERVICE}, {@link #WIFI_P2P_SERVICE},
+     * {@link #WIFI_SERVICE}, {@link #WIFI_AWARE_SERVICE}. For these services this method will
+     * return <code>null</code>.  Generally, if you are running as an instant app you should always
+     * check whether the result of this method is null.
      *
      * @param serviceClass The class of the desired service.
      * @return The service or null if the class is not a supported system service.
@@ -3407,7 +3418,7 @@
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve a
-     * {@link android.app.NotificationManager} for controlling keyguard.
+     * {@link android.app.KeyguardManager} for controlling keyguard.
      *
      * @see #getSystemService(String)
      * @see android.app.KeyguardManager
@@ -3431,7 +3442,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public static final String COUNTRY_DETECTOR = "country_detector";
 
     /**
@@ -3672,15 +3683,6 @@
     public static final String AUDIO_SERVICE = "audio";
 
     /**
-     * Use with {@link #getSystemService(String)}
-     *
-     * @hide
-     * @see #getSystemService(String)
-     * @see com.android.server.biometrics.BiometricPromptService
-     */
-    public static final String BIOMETRIC_PROMPT_SERVICE = "biometric_prompt";
-
-    /**
      * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.hardware.fingerprint.FingerprintManager} for handling management
      * of fingerprints.
@@ -3692,7 +3694,6 @@
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve a
-     * Use with {@link #getSystemService} to retrieve a
      * {@link android.hardware.face.FaceManager} for handling management
      * of face authentication.
      *
@@ -3703,6 +3704,16 @@
     public static final String FACE_SERVICE = "face";
 
     /**
+     * Use with {@link #getSystemService(String)} to retrieve a
+     * {@link android.hardware.biometrics.BiometricManager} for handling management
+     * of face authentication.
+     *
+     * @see #getSystemService
+     * @see android.hardware.biometrics.BiometricManager
+     */
+    public static final String BIOMETRIC_SERVICE = "biometric";
+
+    /**
      * Use with {@link #getSystemService} to retrieve a
      * {@link android.media.MediaRouter} for controlling and managing
      * routing of media.
@@ -3850,6 +3861,14 @@
      */
     public static final String SOUND_TRIGGER_SERVICE = "soundtrigger";
 
+    /**
+     * Official published name of the (internal) permission service.
+     *
+     * @see #getSystemService(String)
+     * @hide
+     */
+    @SystemApi
+    public static final String PERMISSION_SERVICE = "permission";
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve an
@@ -4292,6 +4311,12 @@
     public static final String TIME_ZONE_DETECTOR_SERVICE = "time_zone_detector";
 
     /**
+     * Binder service name for {@link AppBindingService}.
+     * @hide
+     */
+    public static final String APP_BINDING_SERVICE = "app_binding";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
@@ -4792,6 +4817,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public Context createPackageContextAsUser(
             String packageName, @CreatePackageOptions int flags, UserHandle user)
             throws PackageManager.NameNotFoundException {
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index d814e67..044ed61 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -21,6 +21,7 @@
 import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.ICancellationSignal;
@@ -80,7 +81,7 @@
             Bundle opts, ICancellationSignal signal) throws RemoteException, FileNotFoundException;
 
     /* IPC constants */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     static final String descriptor = "android.content.IContentProvider";
 
     @UnsupportedAppUsage
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 212e132..0469a90 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -20,6 +20,7 @@
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.PatternMatcher;
@@ -124,7 +125,7 @@
  *
  * <p><strong>Data Authority</strong> matches if any of the given values match
  * the Intent's data authority <em>and</em> one of the data schemes in the filter
- * has matched the Intent, <em>or</em> no authories were supplied in the filter.
+ * has matched the Intent, <em>or</em> no authorities were supplied in the filter.
  * The Intent authority is determined by calling
  * {@link Intent#getData} and {@link android.net.Uri#getAuthority} on that URI.
  * <em>Note that authority matching here is <b>case sensitive</b>, unlike
@@ -655,7 +656,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public final boolean isVerified() {
         if ((mVerifyState & STATE_NEED_VERIFY_CHECKED) == STATE_NEED_VERIFY_CHECKED) {
             return ((mVerifyState & STATE_NEED_VERIFY) == STATE_NEED_VERIFY);
diff --git a/core/java/android/content/RestrictionsManager.java b/core/java/android/content/RestrictionsManager.java
index 33395ec..bbdab04 100644
--- a/core/java/android/content/RestrictionsManager.java
+++ b/core/java/android/content/RestrictionsManager.java
@@ -25,6 +25,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.PersistableBundle;
 import android.os.RemoteException;
@@ -403,7 +404,7 @@
     private static final String TAG_RESTRICTION = "restriction";
 
     private final Context mContext;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final IRestrictionsManager mService;
 
     /**
diff --git a/core/java/android/content/SyncRequest.java b/core/java/android/content/SyncRequest.java
index fd12d7a..c18b282 100644
--- a/core/java/android/content/SyncRequest.java
+++ b/core/java/android/content/SyncRequest.java
@@ -18,6 +18,7 @@
 
 import android.accounts.Account;
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -33,10 +34,10 @@
     @UnsupportedAppUsage
     private final Account mAccountToSync;
     /** Authority string that corresponds to a ContentProvider. */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final String mAuthority;
     /** Bundle containing user info as well as sync settings. */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final Bundle mExtras;
     /** Don't allow this sync request on metered networks. */
     private final boolean mDisallowMetered;
diff --git a/core/java/android/content/pm/AndroidHidlUpdater.java b/core/java/android/content/pm/AndroidHidlUpdater.java
new file mode 100644
index 0000000..69cc94f
--- /dev/null
+++ b/core/java/android/content/pm/AndroidHidlUpdater.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content.pm;
+
+import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_BASE;
+import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_MANAGER;
+
+import android.content.pm.PackageParser.Package;
+import android.os.Build;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Updates a package to ensure that if it targets <= P that the android.hidl.base-V1.0-java
+ * and android.hidl.manager-V1.0-java libraries are included by default.
+ *
+ * @hide
+ */
+@VisibleForTesting
+public class AndroidHidlUpdater extends PackageSharedLibraryUpdater {
+
+    @Override
+    public void updatePackage(Package pkg) {
+        // This was the default <= P and is maintained for backwards compatibility.
+        if (pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.P) {
+            prefixRequiredLibrary(pkg, ANDROID_HIDL_BASE);
+            prefixRequiredLibrary(pkg, ANDROID_HIDL_MANAGER);
+        }
+    }
+}
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 46877ca..44e652f 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -42,6 +42,7 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -136,7 +137,7 @@
             "android.content.pm.extra.PIN_ITEM_REQUEST";
 
     private final Context mContext;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final ILauncherApps mService;
     @UnsupportedAppUsage
     private final PackageManager mPm;
diff --git a/core/java/android/content/pm/PackageBackwardCompatibility.java b/core/java/android/content/pm/PackageBackwardCompatibility.java
index a16f81b..03eefed 100644
--- a/core/java/android/content/pm/PackageBackwardCompatibility.java
+++ b/core/java/android/content/pm/PackageBackwardCompatibility.java
@@ -53,6 +53,8 @@
                 "android.content.pm.OrgApacheHttpLegacyUpdater",
                 RemoveUnnecessaryOrgApacheHttpLegacyLibrary::new);
 
+        packageUpdaters.add(new AndroidHidlUpdater());
+
         // Add this before adding AndroidTestBaseUpdater so that android.test.base comes before
         // android.test.mock.
         packageUpdaters.add(new AndroidTestRunnerSplitUpdater());
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 316ace1..8fab7bb 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -32,6 +32,7 @@
 import android.content.pm.PackageManager.InstallReason;
 import android.graphics.Bitmap;
 import android.net.Uri;
+import android.os.Build;
 import android.os.FileBridge;
 import android.os.Handler;
 import android.os.Looper;
@@ -960,6 +961,10 @@
          * If the installer is the device owner or the affiliated profile owner, there will be no
          * user intervention.
          *
+         * @param statusReceiver Called when the state of the session changes. Intents
+         *                       sent to this receiver contain {@link #EXTRA_STATUS}. Refer to the
+         *                       individual status codes on how to handle them.
+         *
          * @throws SecurityException if streams opened through
          *             {@link #openWrite(String, long, long)} are still open.
          *
@@ -986,7 +991,9 @@
          * that new properties are added to the session with a new API revision. In this case the
          * callers need to be updated.
          *
-         * @param statusReceiver Callbacks called when the state of the session changes.
+         * @param statusReceiver Called when the state of the session changes. Intents
+         *                       sent to this receiver contain {@link #EXTRA_STATUS}. Refer to the
+         *                       individual status codes on how to handle them.
          *
          * @hide
          */
@@ -1091,7 +1098,7 @@
         public static final int UID_UNKNOWN = -1;
 
         /** {@hide} */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public int mode = MODE_INVALID;
         /** {@hide} */
         @UnsupportedAppUsage
@@ -1104,13 +1111,13 @@
         @UnsupportedAppUsage
         public long sizeBytes = -1;
         /** {@hide} */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public String appPackageName;
         /** {@hide} */
         @UnsupportedAppUsage
         public Bitmap appIcon;
         /** {@hide} */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public String appLabel;
         /** {@hide} */
         public long appIconLastModified = -1;
@@ -1435,40 +1442,40 @@
     public static class SessionInfo implements Parcelable {
 
         /** {@hide} */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public int sessionId;
         /** {@hide} */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public String installerPackageName;
         /** {@hide} */
         @UnsupportedAppUsage
         public String resolvedBaseCodePath;
         /** {@hide} */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public float progress;
         /** {@hide} */
         @UnsupportedAppUsage
         public boolean sealed;
         /** {@hide} */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public boolean active;
 
         /** {@hide} */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public int mode;
         /** {@hide} */
         public @InstallReason int installReason;
         /** {@hide} */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public long sizeBytes;
         /** {@hide} */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public String appPackageName;
         /** {@hide} */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public Bitmap appIcon;
         /** {@hide} */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public CharSequence appLabel;
 
         /** {@hide} */
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index 0c70a3d..19af609 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -22,7 +22,6 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
 import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
@@ -103,8 +102,14 @@
 
     private static volatile boolean sForceSafeLabels = false;
 
-    /** {@hide} */
-    @UnsupportedAppUsage
+    /**
+     * Always use {@link #loadSafeLabel safe labels} when calling {@link #loadLabel}.
+     *
+     * @param forceSafeLabels {@code true} to enforce safe labels
+     *
+     * @hide
+     */
+    @SystemApi
     public static void setForceSafeLabels(boolean forceSafeLabels) {
         sForceSafeLabels = forceSafeLabels;
     }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 1b4878c..a15711f5 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1979,6 +1979,8 @@
      * </ul>
      * A version of 1.1.0 or higher also indicates:
      * <ul>
+     * <li>The {@code VK_ANDROID_external_memory_android_hardware_buffer} extension is
+     *     supported.</li>
      * <li>{@code SYNC_FD} external semaphore and fence handles are supported.</li>
      * <li>{@code VkPhysicalDeviceSamplerYcbcrConversionFeatures::samplerYcbcrConversion} is
      *     supported.</li>
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 20e1454e..b5b4432 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -136,24 +136,6 @@
     public abstract void setVoiceInteractionPackagesProvider(PackagesProvider provider);
 
     /**
-     * Sets the SMS packages provider.
-     * @param provider The packages provider.
-     */
-    public abstract void setSmsAppPackagesProvider(PackagesProvider provider);
-
-    /**
-     * Sets the dialer packages provider.
-     * @param provider The packages provider.
-     */
-    public abstract void setDialerAppPackagesProvider(PackagesProvider provider);
-
-    /**
-     * Sets the sim call manager packages provider.
-     * @param provider The packages provider.
-     */
-    public abstract void setSimCallManagerPackagesProvider(PackagesProvider provider);
-
-    /**
      * Sets the Use Open Wifi packages provider.
      * @param provider The packages provider.
      */
@@ -166,26 +148,28 @@
     public abstract void setSyncAdapterPackagesprovider(SyncAdapterPackagesProvider provider);
 
     /**
-     * Requests granting of the default permissions to the current default SMS app.
-     * @param packageName The default SMS package name.
-     * @param userId The user for which to grant the permissions.
+     * Called when the package for the default dialer changed
+     *
+     * @param packageName the new dialer package
+     * @param userId user for which the change was made
      */
-    public abstract void grantDefaultPermissionsToDefaultSmsApp(String packageName, int userId);
+    public void onDefaultDialerAppChanged(String packageName, int userId) {}
 
     /**
-     * Requests granting of the default permissions to the current default dialer app.
-     * @param packageName The default dialer package name.
-     * @param userId The user for which to grant the permissions.
+     * Called when the package for the default SMS handler changed
+     *
+     * @param packageName the new sms package
+     * @param userId user for which the change was made
      */
-    public abstract void grantDefaultPermissionsToDefaultDialerApp(String packageName, int userId);
+    public void onDefaultSmsAppChanged(String packageName, int userId) {}
 
     /**
-     * Requests granting of the default permissions to the current default sim call manager.
-     * @param packageName The default sim call manager package name.
-     * @param userId The user for which to grant the permissions.
+     * Called when the package for the default sim call manager changed
+     *
+     * @param packageName the new sms package
+     * @param userId user for which the change was made
      */
-    public abstract void grantDefaultPermissionsToDefaultSimCallManager(String packageName,
-            int userId);
+    public void onDefaultSimCallManagerAppChanged(String packageName, int userId) {}
 
     /**
      * Requests granting of the default permissions to the current default Use Open Wifi app.
@@ -446,8 +430,8 @@
          *
          * @param packageName The package to check for
          * @param uid the uid in which the package is running
-         * @return {@link USER_TRUSTED} if the user has trusted the package, {@link USER_BLOCKED}
-         * if user has blocked requests from the package, {@link USER_DEFAULT} if the user response
+         * @return {@link #USER_TRUSTED} if the user has trusted the package, {@link #USER_BLOCKED}
+         * if user has blocked requests from the package, {@link #USER_DEFAULT} if the user response
          * is not yet available
          */
         int getPackageTrustedToInstallApps(String packageName, int uid);
@@ -561,7 +545,7 @@
     /**
      * Returns a list without a change observer.
      *
-     * {@see #getPackageList(PackageListObserver)}
+     * @see #getPackageList(PackageListObserver)
      */
     public @NonNull PackageList getPackageList() {
         return getPackageList(null);
@@ -590,7 +574,16 @@
     /**
      * Returns a package object for the disabled system package name.
      */
-    public abstract @Nullable PackageParser.Package getDisabledPackage(@NonNull String packageName);
+    public abstract @Nullable PackageParser.Package getDisabledSystemPackage(
+            @NonNull String packageName);
+
+    /**
+     * Returns the package name for the disabled system package.
+     *
+     * This is equivalent to
+     * {@link #getDisabledSystemPackage(String)}.{@link PackageParser.Package#packageName}
+     */
+    public abstract @Nullable String getDisabledSystemPackageName(@NonNull String packageName);
 
     /**
      * Returns whether or not the component is the resolver activity.
@@ -619,7 +612,7 @@
      * Access may be limited based upon whether the calling or target applications
      * are instant applications.
      *
-     * @see #canAccessInstantApps(int)
+     * @see #canAccessInstantApps
      */
     public abstract boolean filterAppAccess(
             @Nullable PackageParser.Package pkg, int callingUid, int userId);
@@ -635,6 +628,9 @@
     public abstract void updatePermissionFlagsTEMP(@NonNull String permName,
             @NonNull String packageName, int flagMask, int flagValues, int userId);
 
+    /** Returns whether the given package was signed by the platform */
+    public abstract boolean isPlatformSigned(String pkg);
+
     /**
      * Returns true if it's still safe to restore data backed up from this app's version
      * that was signed with restoringFromSigHash.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 6d49362..1fa5190 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -40,7 +40,6 @@
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
 
-import android.Manifest;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -73,6 +72,7 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
+import android.permission.PermissionManager;
 import android.system.ErrnoException;
 import android.system.OsConstants;
 import android.system.StructStat;
@@ -258,19 +258,6 @@
         }
     }
 
-    /** @hide */
-    public static class SplitPermissionInfo {
-        public final String rootPerm;
-        public final String[] newPerms;
-        public final int targetSdk;
-
-        public SplitPermissionInfo(String rootPerm, String[] newPerms, int targetSdk) {
-            this.rootPerm = rootPerm;
-            this.newPerms = newPerms;
-            this.targetSdk = targetSdk;
-        }
-    }
-
     /**
      * List of new permissions that have been added since 1.0.
      * NOTE: These must be declared in SDK version order, with permissions
@@ -290,34 +277,6 @@
     };
 
     /**
-     * List of permissions that have been split into more granular or dependent
-     * permissions.
-     * @hide
-     */
-    public static final PackageParser.SplitPermissionInfo SPLIT_PERMISSIONS[] =
-        new PackageParser.SplitPermissionInfo[] {
-            // READ_EXTERNAL_STORAGE is always required when an app requests
-            // WRITE_EXTERNAL_STORAGE, because we can't have an app that has
-            // write access without read access.  The hack here with the target
-            // target SDK version ensures that this grant is always done.
-            new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
-                    new String[] { android.Manifest.permission.READ_EXTERNAL_STORAGE },
-                    android.os.Build.VERSION_CODES.CUR_DEVELOPMENT+1),
-            new PackageParser.SplitPermissionInfo(android.Manifest.permission.READ_CONTACTS,
-                    new String[] { android.Manifest.permission.READ_CALL_LOG },
-                    android.os.Build.VERSION_CODES.JELLY_BEAN),
-            new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_CONTACTS,
-                    new String[] { android.Manifest.permission.WRITE_CALL_LOG },
-                    android.os.Build.VERSION_CODES.JELLY_BEAN),
-            new PackageParser.SplitPermissionInfo(Manifest.permission.ACCESS_FINE_LOCATION,
-                    new String[] { android.Manifest.permission.ACCESS_BACKGROUND_LOCATION },
-                    android.os.Build.VERSION_CODES.P0),
-            new PackageParser.SplitPermissionInfo(Manifest.permission.ACCESS_COARSE_LOCATION,
-                    new String[] { android.Manifest.permission.ACCESS_BACKGROUND_LOCATION },
-                    android.os.Build.VERSION_CODES.P0),
-    };
-
-    /**
      * @deprecated callers should move to explicitly passing around source path.
      */
     @Deprecated
@@ -1902,7 +1861,7 @@
      * @throws XmlPullParserException
      * @throws IOException
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private Package parseBaseApk(String apkPath, Resources res, XmlResourceParser parser, int flags,
             String[] outError) throws XmlPullParserException, IOException {
         final String splitName;
@@ -2474,16 +2433,18 @@
             Slog.i(TAG, implicitPerms.toString());
         }
 
-        final int NS = PackageParser.SPLIT_PERMISSIONS.length;
+
+        final int NS = PermissionManager.SPLIT_PERMISSIONS.length;
         for (int is=0; is<NS; is++) {
-            final PackageParser.SplitPermissionInfo spi
-                    = PackageParser.SPLIT_PERMISSIONS[is];
-            if (pkg.applicationInfo.targetSdkVersion >= spi.targetSdk
-                    || !pkg.requestedPermissions.contains(spi.rootPerm)) {
+            final PermissionManager.SplitPermissionInfo spi =
+                    PermissionManager.SPLIT_PERMISSIONS[is];
+            if (pkg.applicationInfo.targetSdkVersion >= spi.getTargetSdk()
+                    || !pkg.requestedPermissions.contains(spi.getRootPermission())) {
                 continue;
             }
-            for (int in=0; in<spi.newPerms.length; in++) {
-                final String perm = spi.newPerms[in];
+            final String[] newPerms = spi.getNewPermissions();
+            for (int in = 0; in < newPerms.length; in++) {
+                final String perm = newPerms[in];
                 if (!pkg.requestedPermissions.contains(perm)) {
                     pkg.requestedPermissions.add(perm);
                 }
diff --git a/core/java/android/content/pm/ParceledListSlice.java b/core/java/android/content/pm/ParceledListSlice.java
index 2eef165..dccc524 100644
--- a/core/java/android/content/pm/ParceledListSlice.java
+++ b/core/java/android/content/pm/ParceledListSlice.java
@@ -17,6 +17,7 @@
 package android.content.pm;
 
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -72,7 +73,7 @@
     }
 
     @SuppressWarnings("unchecked")
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public static final Parcelable.ClassLoaderCreator<ParceledListSlice> CREATOR =
             new Parcelable.ClassLoaderCreator<ParceledListSlice>() {
         public ParceledListSlice createFromParcel(Parcel in) {
diff --git a/core/java/android/content/pm/SharedLibraryNames.java b/core/java/android/content/pm/SharedLibraryNames.java
index 83e8663..387d29e8 100644
--- a/core/java/android/content/pm/SharedLibraryNames.java
+++ b/core/java/android/content/pm/SharedLibraryNames.java
@@ -22,6 +22,10 @@
  */
 public class SharedLibraryNames {
 
+    static final String ANDROID_HIDL_BASE = "android.hidl.base-V1.0-java";
+
+    static final String ANDROID_HIDL_MANAGER = "android.hidl.manager-V1.0-java";
+
     static final String ANDROID_TEST_BASE = "android.test.base";
 
     static final String ANDROID_TEST_MOCK = "android.test.mock";
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 546c213..ec2e2fd 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -30,6 +30,7 @@
 import android.content.res.Resources.NotFoundException;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Icon;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -1243,7 +1244,7 @@
      * @hide
      */
     @Nullable
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public Icon getIcon() {
         return mIcon;
     }
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index 60ac1f0..2d59003 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -26,6 +26,7 @@
 import android.content.Intent;
 import android.content.IntentSender;
 import android.graphics.drawable.AdaptiveIconDrawable;
+import android.os.Build;
 import android.os.Build.VERSION_CODES;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -55,7 +56,7 @@
     private static final String TAG = "ShortcutManager";
 
     private final Context mContext;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final IShortcutService mService;
 
     /**
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 43e1612..88b1c88 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1129,10 +1129,8 @@
      *
      * @throws NotFoundException Throws NotFoundException if the given ID does
      *         not exist or is not a floating-point value.
-     * @hide Pending API council approval.
      */
-    @UnsupportedAppUsage
-    public float getFloat(int id) {
+    public float getFloat(@DimenRes int id) {
         final TypedValue value = obtainTempTypedValue();
         try {
             mResourcesImpl.getValue(id, value, true);
diff --git a/core/java/android/content/res/package.html b/core/java/android/content/res/package.html
index 3d0bac1..3970b16 100644
--- a/core/java/android/content/res/package.html
+++ b/core/java/android/content/res/package.html
@@ -1,7 +1,7 @@
 <HTML>
 <BODY>
 <p>Contains classes for accessing application resources,
-such as raw asset files, colors, drawables, media or other other files
+such as raw asset files, colors, drawables, media, or other files
 in the package, plus important device configuration details
 (orientation, input types, etc.) that affect how the application may behave.</p>
 
@@ -9,4 +9,4 @@
 href="{@docRoot}guide/topics/resources/index.html">Application Resources</a> guide.</p>
 {@more}
 </BODY>
-</HTML>
\ No newline at end of file
+</HTML>
diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java
index c6c2aa5..8bcaa45 100644
--- a/core/java/android/database/AbstractCursor.java
+++ b/core/java/android/database/AbstractCursor.java
@@ -19,6 +19,7 @@
 import android.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.util.Log;
@@ -79,7 +80,7 @@
     private final DataSetObservable mDataSetObservable = new DataSetObservable();
     private final ContentObservable mContentObservable = new ContentObservable();
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private Bundle mExtras = Bundle.EMPTY;
 
     /* -------------------------------------------------------- */
diff --git a/core/java/android/database/sqlite/SQLiteCustomFunction.java b/core/java/android/database/sqlite/SQLiteCustomFunction.java
index ec20458..41b78d3 100644
--- a/core/java/android/database/sqlite/SQLiteCustomFunction.java
+++ b/core/java/android/database/sqlite/SQLiteCustomFunction.java
@@ -17,6 +17,7 @@
 package android.database.sqlite;
 
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 
 /**
  * Describes a custom SQL function.
@@ -24,7 +25,7 @@
  * @hide
  */
 public final class SQLiteCustomFunction {
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public final String name;
     @UnsupportedAppUsage
     public final int numArgs;
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 01557c5..eb5c720 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -649,7 +649,7 @@
      * successful so far. Do not call setTransactionSuccessful before calling this. When this
      * returns a new transaction will have been created but not marked as successful.
      * @return true if the transaction was yielded
-     * @deprecated if the db is locked more than once (becuase of nested transactions) then the lock
+     * @deprecated if the db is locked more than once (because of nested transactions) then the lock
      *   will not be yielded. Use yieldIfContendedSafely instead.
      */
     @Deprecated
diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java
index 1377806..19c6745 100644
--- a/core/java/android/database/sqlite/SQLiteOpenHelper.java
+++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java
@@ -49,7 +49,7 @@
  * <p class="note"><strong>Note:</strong> this class assumes
  * monotonically increasing version numbers for upgrades.</p>
  */
-public abstract class SQLiteOpenHelper {
+public abstract class SQLiteOpenHelper implements AutoCloseable {
     private static final String TAG = SQLiteOpenHelper.class.getSimpleName();
 
     private final Context mContext;
diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
index b705ebb..4fce2d7 100644
--- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java
+++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
@@ -34,6 +34,7 @@
 
 import java.util.Arrays;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
@@ -50,6 +51,8 @@
             Pattern.compile("\\s*\\d+\\s*(,\\s*\\d+\\s*)?");
 
     private Map<String, String> mProjectionMap = null;
+    private List<Pattern> mProjectionGreylist = null;
+
     @UnsupportedAppUsage
     private String mTables = "";
     @UnsupportedAppUsage
@@ -164,6 +167,17 @@
     }
 
     /**
+     * Sets a projection greylist of columns that will be allowed through, even
+     * when {@link #setStrict(boolean)} is enabled. This provides a way for
+     * abusive custom columns like {@code COUNT(*)} to continue working.
+     *
+     * @hide
+     */
+    public void setProjectionGreylist(List<Pattern> projectionGreylist) {
+        mProjectionGreylist = projectionGreylist;
+    }
+
+    /**
      * Sets the cursor factory to be used for the query.  You can use
      * one factory for all queries on a database but it is normally
      * easier to specify the factory when doing this query.
@@ -809,6 +823,24 @@
                         continue;
                     }
 
+                    // If greylist is configured, we might be willing to let
+                    // this custom column bypass our strict checks.
+                    if (mProjectionGreylist != null) {
+                        boolean match = false;
+                        for (Pattern p : mProjectionGreylist) {
+                            if (p.matcher(userColumn).matches()) {
+                                match = true;
+                                break;
+                            }
+                        }
+
+                        if (match) {
+                            Log.w(TAG, "Allowing abusive custom column: " + userColumn);
+                            projection[i] = userColumn;
+                            continue;
+                        }
+                    }
+
                     throw new IllegalArgumentException("Invalid column "
                             + projectionIn[i]);
                 }
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 8e96f56..ac863b2 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -31,6 +31,7 @@
 import android.graphics.SurfaceTexture;
 import android.media.AudioAttributes;
 import android.media.IAudioService;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -165,7 +166,7 @@
     private static final int CAMERA_MSG_PREVIEW_METADATA = 0x400;
     private static final int CAMERA_MSG_FOCUS_MOVE       = 0x800;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private long mNativeContext; // accessed by native methods
     private EventHandler mEventHandler;
     private ShutterCallback mShutterCallback;
@@ -721,7 +722,7 @@
     /**
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public native final void setPreviewSurface(Surface surface) throws IOException;
 
     /**
diff --git a/core/java/android/hardware/HardwareBuffer.java b/core/java/android/hardware/HardwareBuffer.java
index c17aabb..d2c0e7b 100644
--- a/core/java/android/hardware/HardwareBuffer.java
+++ b/core/java/android/hardware/HardwareBuffer.java
@@ -20,6 +20,7 @@
 import android.annotation.LongDef;
 import android.annotation.NonNull;
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -184,7 +185,7 @@
      * Private use only. See {@link #create(int, int, int, int, long)}. May also be
      * called from JNI using an already allocated native <code>HardwareBuffer</code>.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private HardwareBuffer(long nativeObject) {
         mNativeObject = nativeObject;
 
diff --git a/core/java/android/hardware/biometrics/BiometricAuthenticator.java b/core/java/android/hardware/biometrics/BiometricAuthenticator.java
index dbb2527..c604ff1 100644
--- a/core/java/android/hardware/biometrics/BiometricAuthenticator.java
+++ b/core/java/android/hardware/biometrics/BiometricAuthenticator.java
@@ -202,31 +202,6 @@
     }
 
     /**
-     * @param error
-     * @param vendorCode
-     * @return the error string associated with this error
-     */
-    default String getErrorString(int error, int vendorCode) {
-        throw new UnsupportedOperationException("Stub!");
-    }
-
-    /**
-     * @param acquireInfo
-     * @param vendorCode
-     * @return the help string associated with this code
-     */
-    default String getAcquiredString(int acquireInfo, int vendorCode) {
-        throw new UnsupportedOperationException("Stub!");
-    }
-
-    /**
-     * @return one of {@link #TYPE_FINGERPRINT} {@link #TYPE_IRIS} or {@link #TYPE_FACE}
-     */
-    default int getType() {
-        throw new UnsupportedOperationException("Stub!");
-    }
-
-    /**
      * This call warms up the hardware and starts scanning for valid biometrics. It terminates
      * when {@link AuthenticationCallback#onAuthenticationError(int,
      * CharSequence)} is called or when {@link AuthenticationCallback#onAuthenticationSucceeded(
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
new file mode 100644
index 0000000..eea5f9b
--- /dev/null
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics;
+
+import static android.Manifest.permission.USE_BIOMETRIC;
+
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.os.RemoteException;
+
+/**
+ * A class that contains biometric utilities. For authentication, see {@link BiometricPrompt}.
+ */
+public class BiometricManager {
+
+    private final Context mContext;
+    private final IBiometricService mService;
+
+    /**
+     * @hide
+     * @param context
+     * @param service
+     */
+    public BiometricManager(Context context, IBiometricService service) {
+        mContext = context;
+        mService = service;
+    }
+
+    /**
+     * Determine if there is at least one biometric enrolled.
+     *
+     * @return true if at least one biometric is enrolled, false otherwise
+     */
+    @RequiresPermission(USE_BIOMETRIC)
+    public boolean hasEnrolledBiometrics() {
+        try {
+            return mService.hasEnrolledBiometrics(mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+}
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 1cca27d..92a814c 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -225,7 +225,7 @@
 
     private final IBinder mToken = new Binder();
     private final Context mContext;
-    private final IBiometricPromptService mService;
+    private final IBiometricService mService;
     private final Bundle mBundle;
     private final ButtonInfo mPositiveButtonInfo;
     private final ButtonInfo mNegativeButtonInfo;
@@ -250,8 +250,8 @@
         }
     };
 
-    IBiometricPromptServiceReceiver mBiometricPromptServiceReceiver =
-            new IBiometricPromptServiceReceiver.Stub() {
+    IBiometricServiceReceiver mBiometricServiceReceiver =
+            new IBiometricServiceReceiver.Stub() {
 
         @Override
         public void onAuthenticationSucceeded(long deviceId) throws RemoteException {
@@ -290,8 +290,8 @@
         mBundle = bundle;
         mPositiveButtonInfo = positiveButtonInfo;
         mNegativeButtonInfo = negativeButtonInfo;
-        mService = IBiometricPromptService.Stub.asInterface(
-                ServiceManager.getService(Context.BIOMETRIC_PROMPT_SERVICE));
+        mService = IBiometricService.Stub.asInterface(
+                ServiceManager.getService(Context.BIOMETRIC_SERVICE));
     }
 
     /**
@@ -516,7 +516,7 @@
             mAuthenticationCallback = callback;
             final long sessionId = crypto != null ? crypto.getOpId() : 0;
             mService.authenticate(mToken, sessionId, mContext.getUserId(),
-                    mBiometricPromptServiceReceiver, 0 /* flags */, mContext.getOpPackageName(),
+                    mBiometricServiceReceiver, 0 /* flags */, mContext.getOpPackageName(),
                     mBundle, mDialogReceiver);
         } catch (RemoteException e) {
             Log.e(TAG, "Remote exception while authenticating", e);
diff --git a/core/java/android/hardware/biometrics/IBiometricPromptService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl
similarity index 66%
rename from core/java/android/hardware/biometrics/IBiometricPromptService.aidl
rename to core/java/android/hardware/biometrics/IBiometricService.aidl
index 2c93579..fd9d572 100644
--- a/core/java/android/hardware/biometrics/IBiometricPromptService.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricService.aidl
@@ -18,21 +18,25 @@
 
 import android.os.Bundle;
 import android.hardware.biometrics.IBiometricPromptReceiver;
-import android.hardware.biometrics.IBiometricPromptServiceReceiver;
+import android.hardware.biometrics.IBiometricServiceReceiver;
 
 /**
- * Communication channel from BiometricPrompt to BiometricPromptService. The interface does not
- * expose specific biometric modalities. The system will use the default biometric for apps. On
- * devices with more than one, the choice is dictated by user preference in Settings.
+ * Communication channel from BiometricPrompt and BiometricManager to BiometricService. The
+ * interface does not expose specific biometric modalities. The system will use the default
+ * biometric for apps. On devices with more than one, the choice is dictated by user preference in
+ * Settings.
  * @hide
  */
-interface IBiometricPromptService {
+interface IBiometricService {
     // Requests authentication. The service choose the appropriate biometric to use, and show
     // the corresponding BiometricDialog.
     void authenticate(IBinder token, long sessionId, int userId,
-            IBiometricPromptServiceReceiver receiver, int flags, String opPackageName,
+            IBiometricServiceReceiver receiver, int flags, String opPackageName,
             in Bundle bundle, IBiometricPromptReceiver dialogReceiver);
 
     // Cancel authentication for the given sessionId
     void cancelAuthentication(IBinder token, String opPackageName);
+
+    // Returns true if the user has at least one enrolled biometric.
+    boolean hasEnrolledBiometrics(String opPackageName);
 }
\ No newline at end of file
diff --git a/core/java/android/hardware/biometrics/IBiometricPromptServiceReceiver.aidl b/core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl
similarity index 88%
rename from core/java/android/hardware/biometrics/IBiometricPromptServiceReceiver.aidl
rename to core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl
index 1ef6c52..71abdd2 100644
--- a/core/java/android/hardware/biometrics/IBiometricPromptServiceReceiver.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl
@@ -20,10 +20,10 @@
 import android.os.UserHandle;
 
 /**
- * Communication channel from the BiometricPromptService back to BiometricPrompt.
+ * Communication channel from the BiometricService back to BiometricPrompt.
  * @hide
  */
-oneway interface IBiometricPromptServiceReceiver {
+oneway interface IBiometricServiceReceiver {
     void onAuthenticationSucceeded(long deviceId);
     void onAuthenticationFailed(long deviceId);
     void onError(long deviceId, int error, String message);
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 35584ae..46e66e0 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -188,6 +188,7 @@
     @UnsupportedAppUsage
     private final CameraMetadataNative mProperties;
     private List<CameraCharacteristics.Key<?>> mKeys;
+    private List<CameraCharacteristics.Key<?>> mKeysNeedingPermission;
     private List<CaptureRequest.Key<?>> mAvailableRequestKeys;
     private List<CaptureRequest.Key<?>> mAvailableSessionKeys;
     private List<CaptureRequest.Key<?>> mAvailablePhysicalRequestKeys;
@@ -268,11 +269,50 @@
         }
 
         mKeys = Collections.unmodifiableList(
-                getKeys(getClass(), getKeyClass(), this, filterTags));
+                getKeys(getClass(), getKeyClass(), this, filterTags, true));
         return mKeys;
     }
 
     /**
+     * <p>Returns a subset of the list returned by {@link #getKeys} with all keys that
+     * require camera clients to obtain the {@link android.Manifest.permission#CAMERA} permission.
+     * </p>
+     *
+     * <p>If an application calls {@link CameraManager#getCameraCharacteristics} without holding the
+     * {@link android.Manifest.permission#CAMERA} permission,
+     * all keys in this list will not be available, and calling {@link #get} will
+     * return null for those keys. If the application obtains the
+     * {@link android.Manifest.permission#CAMERA} permission, then the
+     * CameraCharacteristics from a call to a subsequent
+     * {@link CameraManager#getCameraCharacteristics} will have the keys available.</p>
+     *
+     * <p>The list returned is not modifiable, so any attempts to modify it will throw
+     * a {@code UnsupportedOperationException}.</p>
+     *
+     * <p>Each key is only listed once in the list. The order of the keys is undefined.</p>
+     *
+     * @return List of camera characteristic keys that require the
+     *         {@link android.Manifest.permission#CAMERA} permission. The list can be null in case
+     *         there are no currently present keys that need additional permission.
+     */
+    public List<Key<?>> getKeysNeedingPermission() {
+        if (mKeysNeedingPermission == null) {
+            Object crKey = CameraCharacteristics.Key.class;
+            Class<CameraCharacteristics.Key<?>> crKeyTyped =
+                (Class<CameraCharacteristics.Key<?>>)crKey;
+
+            int[] filterTags = get(REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION);
+            if (filterTags == null) {
+                return null;
+            }
+            mKeysNeedingPermission =
+                getAvailableKeyList(CameraCharacteristics.class, crKeyTyped, filterTags,
+                        /*includeSynthetic*/ false);
+        }
+        return mKeysNeedingPermission;
+    }
+
+    /**
      * <p>Returns a subset of {@link #getAvailableCaptureRequestKeys} keys that the
      * camera device can pass as part of the capture session initialization.</p>
      *
@@ -328,17 +368,18 @@
                 return null;
             }
             mAvailableSessionKeys =
-                    getAvailableKeyList(CaptureRequest.class, crKeyTyped, filterTags);
+                    getAvailableKeyList(CaptureRequest.class, crKeyTyped, filterTags,
+                            /*includeSynthetic*/ false);
         }
         return mAvailableSessionKeys;
     }
 
     /**
      * <p>Returns a subset of {@link #getAvailableCaptureRequestKeys} keys that can
-     * be overriden for physical devices backing a logical multi-camera.</p>
+     * be overridden for physical devices backing a logical multi-camera.</p>
      *
      * <p>This is a subset of android.request.availableRequestKeys which contains a list
-     * of keys that can be overriden using {@link CaptureRequest.Builder#setPhysicalCameraKey }.
+     * of keys that can be overridden using {@link CaptureRequest.Builder#setPhysicalCameraKey }.
      * The respective value of such request key can be obtained by calling
      * {@link CaptureRequest.Builder#getPhysicalCameraKey }. Capture requests that contain
      * individual physical device requests must be built via
@@ -353,7 +394,7 @@
      *
      * <p>Each key is only listed once in the list. The order of the keys is undefined.</p>
      *
-     * @return List of keys that can be overriden in individual physical device requests.
+     * @return List of keys that can be overridden in individual physical device requests.
      * In case the camera device doesn't support such keys the list can be null.
      */
     @SuppressWarnings({"unchecked"})
@@ -367,7 +408,8 @@
                 return null;
             }
             mAvailablePhysicalRequestKeys =
-                    getAvailableKeyList(CaptureRequest.class, crKeyTyped, filterTags);
+                    getAvailableKeyList(CaptureRequest.class, crKeyTyped, filterTags,
+                            /*includeSynthetic*/ false);
         }
         return mAvailablePhysicalRequestKeys;
     }
@@ -399,7 +441,8 @@
                         + "in the characteristics");
             }
             mAvailableRequestKeys =
-                    getAvailableKeyList(CaptureRequest.class, crKeyTyped, filterTags);
+                    getAvailableKeyList(CaptureRequest.class, crKeyTyped, filterTags,
+                            /*includeSynthetic*/ true);
         }
         return mAvailableRequestKeys;
     }
@@ -430,7 +473,8 @@
                 throw new AssertionError("android.request.availableResultKeys must be non-null "
                         + "in the characteristics");
             }
-            mAvailableResultKeys = getAvailableKeyList(CaptureResult.class, crKeyTyped, filterTags);
+            mAvailableResultKeys = getAvailableKeyList(CaptureResult.class, crKeyTyped, filterTags,
+                    /*includeSynthetic*/ true);
         }
         return mAvailableResultKeys;
     }
@@ -445,13 +489,16 @@
      *
      * @param metadataClass The subclass of CameraMetadata that you want to get the keys for.
      * @param keyClass The class of the metadata key, e.g. CaptureRequest.Key.class
+     * @param filterTags An array of tags to be used for filtering
+     * @param includeSynthetic Include public syntethic tag by default.
      *
      * @return List of keys supported by this CameraDevice for metadataClass.
      *
      * @throws IllegalArgumentException if metadataClass is not a subclass of CameraMetadata
      */
     private <TKey> List<TKey>
-    getAvailableKeyList(Class<?> metadataClass, Class<TKey> keyClass, int[] filterTags) {
+    getAvailableKeyList(Class<?> metadataClass, Class<TKey> keyClass, int[] filterTags,
+            boolean includeSynthetic) {
 
         if (metadataClass.equals(CameraMetadata.class)) {
             throw new AssertionError(
@@ -462,7 +509,7 @@
         }
 
         List<TKey> staticKeyList = getKeys(
-                metadataClass, keyClass, /*instance*/null, filterTags);
+                metadataClass, keyClass, /*instance*/null, filterTags, includeSynthetic);
         return Collections.unmodifiableList(staticKeyList);
     }
 
@@ -474,6 +521,13 @@
      * REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA capability. If the camera device
      * doesn't have the capability, the return value will be an empty set. </p>
      *
+     * <p>Prior to API level 29, all returned IDs are guaranteed to be returned by {@link
+     * CameraManager#getCameraIdList}, and can be opened directly by
+     * {@link CameraManager#openCamera}. Starting from API level 29, for each of the returned ID,
+     * if it's also returned by {@link CameraManager#getCameraIdList}, it can be used as a
+     * standalone camera by {@link CameraManager#openCamera}. Otherwise, the camera ID can only be
+     * used as part of the current logical camera.</p>
+     *
      * <p>The set returned is not modifiable, so any attempts to modify it will throw
      * a {@code UnsupportedOperationException}.</p>
      *
@@ -1103,6 +1157,7 @@
      * <p><b>Limited capability</b> -
      * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
      * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
      * @see CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION
@@ -1124,6 +1179,7 @@
      * <p><b>Limited capability</b> -
      * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
      * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
      * @see CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION
@@ -1238,6 +1294,7 @@
      * <p><b>Units</b>:
      * Quaternion coefficients</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      */
     @PublicKey
     public static final Key<float[]> LENS_POSE_ROTATION =
@@ -1273,6 +1330,7 @@
      * with PRIMARY_CAMERA.</p>
      * <p><b>Units</b>: Meters</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#LENS_DISTORTION
      * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
@@ -1344,6 +1402,7 @@
      * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}
      * coordinate system.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#LENS_DISTORTION
      * @see CameraCharacteristics#LENS_POSE_ROTATION
@@ -1387,6 +1446,7 @@
      * <p><b>Units</b>:
      * Unitless coefficients.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
      * @deprecated
@@ -1411,6 +1471,7 @@
      *   <li>{@link #LENS_POSE_REFERENCE_GYROSCOPE GYROSCOPE}</li>
      * </ul></p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#LENS_POSE_TRANSLATION
      * @see #LENS_POSE_REFERENCE_PRIMARY_CAMERA
@@ -1452,6 +1513,7 @@
      * <p><b>Units</b>:
      * Unitless coefficients.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
      * @see CameraCharacteristics#LENS_RADIAL_DISTORTION
@@ -1860,10 +1922,10 @@
             new Key<int[]>("android.request.availableSessionKeys", int[].class);
 
     /**
-     * <p>A subset of the available request keys that can be overriden for
+     * <p>A subset of the available request keys that can be overridden for
      * physical devices backing a logical multi-camera.</p>
      * <p>This is a subset of android.request.availableRequestKeys which contains a list
-     * of keys that can be overriden using {@link CaptureRequest.Builder#setPhysicalCameraKey }.
+     * of keys that can be overridden using {@link CaptureRequest.Builder#setPhysicalCameraKey }.
      * The respective value of such request key can be obtained by calling
      * {@link CaptureRequest.Builder#getPhysicalCameraKey }. Capture requests that contain
      * individual physical device requests must be built via
@@ -1880,6 +1942,21 @@
             new Key<int[]>("android.request.availablePhysicalCameraRequestKeys", int[].class);
 
     /**
+     * <p>A list of camera characteristics keys that are only available
+     * in case the camera client has camera permission.</p>
+     * <p>The entry contains a subset of
+     * {@link android.hardware.camera2.CameraCharacteristics#getKeys } that require camera clients
+     * to acquire the {@link android.Manifest.permission#CAMERA } permission before calling
+     * {@link android.hardware.camera2.CameraManager#getCameraCharacteristics }. If the
+     * permission is not held by the camera client, then the values of the repsective properties
+     * will not be present in {@link android.hardware.camera2.CameraCharacteristics }.</p>
+     * <p>This key is available on all devices.</p>
+     * @hide
+     */
+    public static final Key<int[]> REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION =
+            new Key<int[]>("android.request.characteristicKeysNeedingPermission", int[].class);
+
+    /**
      * <p>The list of image formats that are supported by this
      * camera device for output streams.</p>
      * <p>All camera devices will support JPEG and YUV_420_888 formats.</p>
@@ -2703,6 +2780,7 @@
      *   <li>{@link #SENSOR_REFERENCE_ILLUMINANT1_ISO_STUDIO_TUNGSTEN ISO_STUDIO_TUNGSTEN}</li>
      * </ul></p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#SENSOR_CALIBRATION_TRANSFORM1
      * @see CameraCharacteristics#SENSOR_COLOR_TRANSFORM1
@@ -2744,6 +2822,7 @@
      * <p><b>Range of valid values:</b><br>
      * Any value listed in {@link CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT1 android.sensor.referenceIlluminant1}</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#SENSOR_CALIBRATION_TRANSFORM2
      * @see CameraCharacteristics#SENSOR_COLOR_TRANSFORM2
@@ -2766,6 +2845,7 @@
      * space under the first reference illuminant
      * ({@link CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT1 android.sensor.referenceIlluminant1}).</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT1
      */
@@ -2788,6 +2868,7 @@
      * <p>This matrix will only be present if the second reference
      * illuminant is present.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT2
      */
@@ -2811,6 +2892,7 @@
      * match the standard white point for the first reference illuminant
      * (i.e. no chromatic adaptation will be applied by this transform).</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT1
      */
@@ -2836,6 +2918,7 @@
      * <p>This matrix will only be present if the second reference
      * illuminant is present.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT2
      */
@@ -2857,6 +2940,7 @@
      * illuminant in the reference sensor colorspace is mapped to D50 in the
      * CIE XYZ colorspace.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT1
      */
@@ -2880,6 +2964,7 @@
      * <p>This matrix will only be present if the second reference
      * illuminant is present.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT2
      */
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 7ebe0f9..44d7364 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -34,7 +34,6 @@
 import android.os.DeadObjectException;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Looper;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceSpecificException;
@@ -45,7 +44,6 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
-
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
 import java.util.concurrent.RejectedExecutionException;
@@ -97,6 +95,9 @@
      * identifiers, while removable cameras have a unique identifier for each
      * individual device, even if they are the same model.</p>
      *
+     * <p>This list doesn't contain physical cameras that can only used as part of a logical
+     * multi-camera device.</p>
+     *
      * @return The list of currently connected camera devices.
      */
     @NonNull
@@ -234,7 +235,13 @@
      * <p>Query the capabilities of a camera device. These capabilities are
      * immutable for a given camera.</p>
      *
-     * @param cameraId The id of the camera device to query
+     * <p>From API level 29, this function can also be used to query the capabilities of physical
+     * cameras that can only be used as part of logical multi-camera. These cameras cannot not be
+     * opened directly via {@link #openCamera}</p>
+     *
+     * @param cameraId The id of the camera device to query. This could be either a standalone
+     * camera ID which can be directly opened by {@link #openCamera}, or a physical camera ID that
+     * can only used as part of a logical multi-camera.
      * @return The properties of the given camera
      *
      * @throws IllegalArgumentException if the cameraId does not match any
@@ -262,7 +269,9 @@
                         "Camera service is currently unavailable");
             }
             try {
-                if (!supportsCamera2ApiLocked(cameraId)) {
+                // First check isHiddenPhysicalCamera to avoid supportsCamera2ApiLocked throwing
+                // exception in case cameraId is a hidden physical camera.
+                if (!isHiddenPhysicalCamera(cameraId) && !supportsCamera2ApiLocked(cameraId)) {
                     // Legacy backwards compatibility path; build static info from the camera
                     // parameters
                     int id = Integer.parseInt(cameraId);
@@ -454,7 +463,7 @@
      *
      * @throws IllegalArgumentException if cameraId or the callback was null,
      * or the cameraId does not match any currently or previously available
-     * camera device.
+     * camera device returned by {@link #getCameraIdList}.
      *
      * @throws SecurityException if the application does not have permission to
      * access the camera
@@ -778,6 +787,29 @@
     }
 
     /**
+     * Queries the camera service if a cameraId is a hidden physical camera that belongs to a
+     * logical camera device.
+     *
+     * A hidden physical camera is a camera that cannot be opened by the application. But it
+     * can be used as part of a logical camera.
+     *
+     * @param cameraId a non-{@code null} camera identifier
+     * @return {@code true} if cameraId is a hidden physical camera device
+     */
+    private boolean isHiddenPhysicalCamera(String cameraId) {
+        try {
+            ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
+            // If no camera service, no support
+            if (cameraService == null) return false;
+
+            return cameraService.isHiddenPhysicalCamera(cameraId);
+        } catch (RemoteException e) {
+            // Camera service is now down, no support for any API level
+        }
+        return false;
+    }
+
+    /**
      * A per-process global camera manager instance, to retain a connection to the camera service,
      * and to distribute camera availability notices to API-registered callbacks
      */
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index caa99d5..486b054 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -116,7 +116,8 @@
     public List<TKey> getKeys() {
         Class<CameraMetadata<TKey>> thisClass = (Class<CameraMetadata<TKey>>) getClass();
         return Collections.unmodifiableList(
-                getKeys(thisClass, getKeyClass(), this, /*filterTags*/null));
+                getKeys(thisClass, getKeyClass(), this, /*filterTags*/null,
+                    /*includeSynthetic*/ true));
     }
 
     /**
@@ -131,13 +132,14 @@
      * Optionally, if {@code filterTags} is not {@code null}, then filter out any keys
      * whose native {@code tag} is not in {@code filterTags}. The {@code filterTags} array will be
      * sorted as a side effect.
+     * {@code includeSynthetic} Includes public syntenthic fields by default.
      * </p>
      */
      /*package*/ @SuppressWarnings("unchecked")
     <TKey> ArrayList<TKey> getKeys(
              Class<?> type, Class<TKey> keyClass,
              CameraMetadata<TKey> instance,
-             int[] filterTags) {
+             int[] filterTags, boolean includeSynthetic) {
 
         if (DEBUG) Log.v(TAG, "getKeysStatic for " + type);
 
@@ -168,7 +170,7 @@
                 }
 
                 if (instance == null || instance.getProtected(key) != null) {
-                    if (shouldKeyBeAdded(key, field, filterTags)) {
+                    if (shouldKeyBeAdded(key, field, filterTags, includeSynthetic)) {
                         keyList.add(key);
 
                         if (DEBUG) {
@@ -215,7 +217,8 @@
     }
 
     @SuppressWarnings("rawtypes")
-    private static <TKey> boolean shouldKeyBeAdded(TKey key, Field field, int[] filterTags) {
+    private static <TKey> boolean shouldKeyBeAdded(TKey key, Field field, int[] filterTags,
+            boolean includeSynthetic) {
         if (key == null) {
             throw new NullPointerException("key must not be null");
         }
@@ -249,8 +252,7 @@
         if (field.getAnnotation(SyntheticKey.class) != null) {
             // This key is synthetic, so calling #getTag will throw IAE
 
-            // TODO: don't just assume all public+synthetic keys are always available
-            return true;
+            return includeSynthetic;
         }
 
         /*
@@ -811,8 +813,14 @@
     public static final int REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING = 10;
 
     /**
-     * <p>The camera device is a logical camera backed by two or more physical cameras that are
-     * also exposed to the application.</p>
+     * <p>The camera device is a logical camera backed by two or more physical cameras. In
+     * API level 28, the physical cameras must also be exposed to the application via
+     * {@link android.hardware.camera2.CameraManager#getCameraIdList }. Starting from API
+     * level 29, some or all physical cameras may not be independently exposed to the
+     * application, in which case the physical camera IDs will not be available in
+     * {@link android.hardware.camera2.CameraManager#getCameraIdList }. But the application
+     * can still query the physical cameras' characteristics by calling
+     * {@link android.hardware.camera2.CameraManager#getCameraCharacteristics }.</p>
      * <p>Camera application shouldn't assume that there are at most 1 rear camera and 1 front
      * camera in the system. For an application that switches between front and back cameras,
      * the recommendation is to switch between the first rear camera and the first front
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 3c6c11d..a7e185c 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2841,6 +2841,7 @@
      * <p><b>Units</b>:
      * Quaternion coefficients</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      */
     @PublicKey
     public static final Key<float[]> LENS_POSE_ROTATION =
@@ -2876,6 +2877,7 @@
      * with PRIMARY_CAMERA.</p>
      * <p><b>Units</b>: Meters</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#LENS_DISTORTION
      * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
@@ -2947,6 +2949,7 @@
      * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}
      * coordinate system.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#LENS_DISTORTION
      * @see CameraCharacteristics#LENS_POSE_ROTATION
@@ -2990,6 +2993,7 @@
      * <p><b>Units</b>:
      * Unitless coefficients.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
      * @deprecated
@@ -3036,6 +3040,7 @@
      * <p><b>Units</b>:
      * Unitless coefficients.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
      * @see CameraCharacteristics#LENS_RADIAL_DISTORTION
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index d967fba..7810e6c 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -1889,7 +1889,7 @@
             final long ident = Binder.clearCallingIdentity();
             try {
                 CameraDeviceImpl.this.mDeviceExecutor.execute(obtainRunnable(
-                            CameraDeviceCallbacks::notifyError, this, code));
+                            CameraDeviceCallbacks::notifyError, this, code).recycleOnUse());
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
diff --git a/core/java/android/hardware/camera2/utils/CloseableLock.java b/core/java/android/hardware/camera2/utils/CloseableLock.java
index 9ac89c8..3b8beac 100644
--- a/core/java/android/hardware/camera2/utils/CloseableLock.java
+++ b/core/java/android/hardware/camera2/utils/CloseableLock.java
@@ -290,7 +290,7 @@
     /**
      * Release a single lock that was acquired.
      *
-     * <p>Any other other that is blocked and trying to acquire a lock will get a chance
+     * <p>Any other thread that is blocked and trying to acquire a lock will get a chance
      * to acquire the lock.</p>
      *
      * @throws IllegalStateException if no locks were acquired, or if the lock was already closed
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 0f83c8b..873a24a 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -168,10 +168,11 @@
             } catch (RemoteException e) {
                 Log.w(TAG, "Remote exception while authenticating: ", e);
                 if (callback != null) {
-                    // Though this may not be a hardware issue, it will cause apps to give up or try
-                    // again later.
+                    // Though this may not be a hardware issue, it will cause apps to give up or
+                    // try again later.
                     callback.onAuthenticationError(FACE_ERROR_HW_UNAVAILABLE,
-                            getErrorString(FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
+                            getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE,
+                                0 /* vendorCode */));
                 }
             }
         }
@@ -232,27 +233,28 @@
             } catch (RemoteException e) {
                 Log.w(TAG, "Remote exception in enroll: ", e);
                 if (callback != null) {
-                    // Though this may not be a hardware issue, it will cause apps to give up or try
-                    // again later.
+                    // Though this may not be a hardware issue, it will cause apps to give up or
+                    // try again later.
                     callback.onEnrollmentError(FACE_ERROR_HW_UNAVAILABLE,
-                            getErrorString(FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
+                            getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE,
+                                0 /* vendorCode */));
                 }
             }
         }
     }
 
     /**
-     * Requests a pre-enrollment auth token to tie enrollment to the confirmation of
+     * Requests an auth token to tie sensitive operations to the confirmation of
      * existing device credentials (e.g. pin/pattern/password).
      *
      * @hide
      */
     @RequiresPermission(MANAGE_BIOMETRIC)
-    public long preEnroll() {
+    public long generateChallenge() {
         long result = 0;
         if (mService != null) {
             try {
-                result = mService.preEnroll(mToken);
+                result = mService.generateChallenge(mToken);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -261,16 +263,46 @@
     }
 
     /**
-     * Finishes enrollment and cancels the current auth token.
+     * Invalidates the current auth token.
      *
      * @hide
      */
     @RequiresPermission(MANAGE_BIOMETRIC)
-    public int postEnroll() {
+    public int revokeChallenge() {
         int result = 0;
         if (mService != null) {
             try {
-                result = mService.postEnroll(mToken);
+                result = mService.revokeChallenge(mToken);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return result;
+    }
+
+    /**
+     * @hide
+     */
+    @RequiresPermission(MANAGE_BIOMETRIC)
+    public void setRequireAttention(boolean requireAttention, byte[] token) {
+        if (mService != null) {
+            try {
+                mService.setRequireAttention(requireAttention, token);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @RequiresPermission(MANAGE_BIOMETRIC)
+    public boolean getRequireAttention(byte[] token) {
+        boolean result = true;
+        if (mService != null) {
+            try {
+                mService.getRequireAttention(token);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -315,7 +347,8 @@
                 Log.w(TAG, "Remote exception in remove: ", e);
                 if (callback != null) {
                     callback.onRemovalError(face, FACE_ERROR_HW_UNAVAILABLE,
-                            getErrorString(FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
+                            getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE,
+                                0 /* vendorCode */));
                 }
             }
         }
@@ -513,32 +546,36 @@
         }
     }
 
-    @Override
-    public String getErrorString(int errMsg, int vendorCode) {
+    /**
+     * @hide
+     */
+    public static String getErrorString(Context context, int errMsg, int vendorCode) {
         switch (errMsg) {
-            case FACE_ERROR_HW_UNAVAILABLE:
-                return mContext.getString(
-                        com.android.internal.R.string.face_error_hw_not_available);
             case FACE_ERROR_UNABLE_TO_PROCESS:
-                return mContext.getString(
+                return context.getString(
                         com.android.internal.R.string.face_error_unable_to_process);
-            case FACE_ERROR_TIMEOUT:
-                return mContext.getString(com.android.internal.R.string.face_error_timeout);
+            case FACE_ERROR_HW_UNAVAILABLE:
+                return context.getString(
+                        com.android.internal.R.string.face_error_hw_not_available);
             case FACE_ERROR_NO_SPACE:
-                return mContext.getString(com.android.internal.R.string.face_error_no_space);
+                return context.getString(com.android.internal.R.string.face_error_no_space);
+            case FACE_ERROR_TIMEOUT:
+                return context.getString(com.android.internal.R.string.face_error_timeout);
             case FACE_ERROR_CANCELED:
-                return mContext.getString(com.android.internal.R.string.face_error_canceled);
+                return context.getString(com.android.internal.R.string.face_error_canceled);
             case FACE_ERROR_LOCKOUT:
-                return mContext.getString(com.android.internal.R.string.face_error_lockout);
+                return context.getString(com.android.internal.R.string.face_error_lockout);
             case FACE_ERROR_LOCKOUT_PERMANENT:
-                return mContext.getString(
+                return context.getString(
                         com.android.internal.R.string.face_error_lockout_permanent);
+            case FACE_ERROR_USER_CANCELED:
+                return context.getString(com.android.internal.R.string.face_error_user_canceled);
             case FACE_ERROR_NOT_ENROLLED:
-                return mContext.getString(com.android.internal.R.string.face_error_not_enrolled);
+                return context.getString(com.android.internal.R.string.face_error_not_enrolled);
             case FACE_ERROR_HW_NOT_PRESENT:
-                return mContext.getString(com.android.internal.R.string.face_error_hw_not_present);
+                return context.getString(com.android.internal.R.string.face_error_hw_not_present);
             case FACE_ERROR_VENDOR: {
-                String[] msgArray = mContext.getResources().getStringArray(
+                String[] msgArray = context.getResources().getStringArray(
                         com.android.internal.R.array.face_error_vendor);
                 if (vendorCode < msgArray.length) {
                     return msgArray[vendorCode];
@@ -552,35 +589,34 @@
     /**
      * @hide
      */
-    @Override
-    public String getAcquiredString(int acquireInfo, int vendorCode) {
+    public static String getAcquiredString(Context context, int acquireInfo, int vendorCode) {
         switch (acquireInfo) {
             case FACE_ACQUIRED_GOOD:
                 return null;
             case FACE_ACQUIRED_INSUFFICIENT:
-                return mContext.getString(R.string.face_acquired_insufficient);
+                return context.getString(R.string.face_acquired_insufficient);
             case FACE_ACQUIRED_TOO_BRIGHT:
-                return mContext.getString(R.string.face_acquired_too_bright);
+                return context.getString(R.string.face_acquired_too_bright);
             case FACE_ACQUIRED_TOO_DARK:
-                return mContext.getString(R.string.face_acquired_too_dark);
+                return context.getString(R.string.face_acquired_too_dark);
             case FACE_ACQUIRED_TOO_CLOSE:
-                return mContext.getString(R.string.face_acquired_too_close);
+                return context.getString(R.string.face_acquired_too_close);
             case FACE_ACQUIRED_TOO_FAR:
-                return mContext.getString(R.string.face_acquired_too_far);
+                return context.getString(R.string.face_acquired_too_far);
             case FACE_ACQUIRED_TOO_HIGH:
-                return mContext.getString(R.string.face_acquired_too_high);
+                return context.getString(R.string.face_acquired_too_high);
             case FACE_ACQUIRED_TOO_LOW:
-                return mContext.getString(R.string.face_acquired_too_low);
+                return context.getString(R.string.face_acquired_too_low);
             case FACE_ACQUIRED_TOO_RIGHT:
-                return mContext.getString(R.string.face_acquired_too_right);
+                return context.getString(R.string.face_acquired_too_right);
             case FACE_ACQUIRED_TOO_LEFT:
-                return mContext.getString(R.string.face_acquired_too_left);
+                return context.getString(R.string.face_acquired_too_left);
             case FACE_ACQUIRED_POOR_GAZE:
-                return mContext.getString(R.string.face_acquired_poor_gaze);
+                return context.getString(R.string.face_acquired_poor_gaze);
             case FACE_ACQUIRED_NOT_DETECTED:
-                return mContext.getString(R.string.face_acquired_not_detected);
+                return context.getString(R.string.face_acquired_not_detected);
             case FACE_ACQUIRED_VENDOR: {
-                String[] msgArray = mContext.getResources().getStringArray(
+                String[] msgArray = context.getResources().getStringArray(
                         R.array.face_acquired_vendor);
                 if (vendorCode < msgArray.length) {
                     return msgArray[vendorCode];
@@ -592,18 +628,10 @@
     }
 
     /**
-     * @hide
-     */
-    @Override
-    public int getType() {
-        return TYPE_FACE;
-    }
-
-    /**
      * Used so BiometricPrompt can map the face ones onto existing public constants.
      * @hide
      */
-    public int getMappedAcquiredInfo(int acquireInfo, int vendorCode) {
+    public static int getMappedAcquiredInfo(int acquireInfo, int vendorCode) {
         switch (acquireInfo) {
             case FACE_ACQUIRED_GOOD:
                 return BiometricConstants.BIOMETRIC_ACQUIRED_GOOD;
@@ -898,13 +926,13 @@
                 ? (vendorCode + FACE_ERROR_VENDOR_BASE) : errMsgId;
         if (mEnrollmentCallback != null) {
             mEnrollmentCallback.onEnrollmentError(clientErrMsgId,
-                    getErrorString(errMsgId, vendorCode));
+                    getErrorString(mContext, errMsgId, vendorCode));
         } else if (mAuthenticationCallback != null) {
             mAuthenticationCallback.onAuthenticationError(clientErrMsgId,
-                    getErrorString(errMsgId, vendorCode));
+                    getErrorString(mContext, errMsgId, vendorCode));
         } else if (mRemovalCallback != null) {
             mRemovalCallback.onRemovalError(mRemovalFace, clientErrMsgId,
-                    getErrorString(errMsgId, vendorCode));
+                    getErrorString(mContext, errMsgId, vendorCode));
         }
     }
 
@@ -932,7 +960,7 @@
         if (mAuthenticationCallback != null) {
             mAuthenticationCallback.onAuthenticationAcquired(acquireInfo);
         }
-        final String msg = getAcquiredString(acquireInfo, vendorCode);
+        final String msg = getAcquiredString(mContext, acquireInfo, vendorCode);
         if (msg == null) {
             return;
         }
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index dd995c9..6681bd7 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -17,7 +17,7 @@
 
 import android.os.Bundle;
 import android.hardware.biometrics.IBiometricPromptReceiver;
-import android.hardware.biometrics.IBiometricPromptServiceReceiver;
+import android.hardware.biometrics.IBiometricServiceReceiver;
 import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
 import android.hardware.face.IFaceServiceReceiver;
 import android.hardware.face.Face;
@@ -34,8 +34,8 @@
 
     // This method invokes the BiometricDialog. The arguments are almost the same as above,
     // but should only be called from (BiometricPromptService).
-    void authenticateFromService(IBinder token, long sessionId, int userId,
-            IBiometricPromptServiceReceiver receiver, int flags, String opPackageName,
+    void authenticateFromService(boolean requireConfirmation, IBinder token, long sessionId,
+            int userId, IBiometricServiceReceiver receiver, int flags, String opPackageName,
             in Bundle bundle, IBiometricPromptReceiver dialogReceiver,
             int callingUid, int callingPid, int callingUserId);
 
@@ -66,10 +66,10 @@
     boolean isHardwareDetected(long deviceId, String opPackageName);
 
     // Get a pre-enrollment authentication token
-    long preEnroll(IBinder token);
+    long generateChallenge(IBinder token);
 
     // Finish an enrollment sequence and invalidate the authentication token
-    int postEnroll(IBinder token);
+    int revokeChallenge(IBinder token);
 
     // Determine if a user has at least one enrolled face
     boolean hasEnrolledFaces(int userId, String opPackageName);
@@ -94,4 +94,8 @@
 
     // Enumerate all faces
     void enumerate(IBinder token, int userId, IFaceServiceReceiver receiver);
+
+    int setRequireAttention(boolean requireAttention, in byte [] token);
+
+    boolean getRequireAttention(in byte [] token);
 }
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index b380a2e..a4f3ce1 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -426,7 +426,8 @@
                 // Though this may not be a hardware issue, it will cause apps to give up or try
                 // again later.
                 callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
-                        getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
+                        getErrorString(mContext, FINGERPRINT_ERROR_HW_UNAVAILABLE,
+                            0 /* vendorCode */));
             }
         }
     }
@@ -476,7 +477,8 @@
                 // Though this may not be a hardware issue, it will cause apps to give up or try
                 // again later.
                 callback.onEnrollmentError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
-                        getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
+                        getErrorString(mContext, FINGERPRINT_ERROR_HW_UNAVAILABLE,
+                            0 /* vendorCode */));
             }
         }
     }
@@ -546,7 +548,8 @@
             Slog.w(TAG, "Remote exception in remove: ", e);
             if (callback != null) {
                 callback.onRemovalError(fp, FINGERPRINT_ERROR_HW_UNAVAILABLE,
-                        getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
+                        getErrorString(mContext, FINGERPRINT_ERROR_HW_UNAVAILABLE,
+                            0 /* vendorCode */));
             }
         }
     }
@@ -568,7 +571,8 @@
             Slog.w(TAG, "Remote exception in enumerate: ", e);
             if (callback != null) {
                 callback.onEnumerateError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
-                        getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
+                        getErrorString(mContext, FINGERPRINT_ERROR_HW_UNAVAILABLE,
+                            0 /* vendorCode */));
             }
         }
     }
@@ -862,7 +866,7 @@
         if (mAuthenticationCallback != null) {
             mAuthenticationCallback.onAuthenticationAcquired(acquireInfo);
         }
-        final String msg = getAcquiredString(acquireInfo, vendorCode);
+        final String msg = getAcquiredString(mContext, acquireInfo, vendorCode);
         if (msg == null) {
             return;
         }
@@ -882,16 +886,16 @@
                 ? (vendorCode + FINGERPRINT_ERROR_VENDOR_BASE) : errMsgId;
         if (mEnrollmentCallback != null) {
             mEnrollmentCallback.onEnrollmentError(clientErrMsgId,
-                    getErrorString(errMsgId, vendorCode));
+                    getErrorString(mContext, errMsgId, vendorCode));
         } else if (mAuthenticationCallback != null) {
             mAuthenticationCallback.onAuthenticationError(clientErrMsgId,
-                    getErrorString(errMsgId, vendorCode));
+                    getErrorString(mContext, errMsgId, vendorCode));
         } else if (mRemovalCallback != null) {
             mRemovalCallback.onRemovalError(mRemovalFingerprint, clientErrMsgId,
-                    getErrorString(errMsgId, vendorCode));
+                    getErrorString(mContext, errMsgId, vendorCode));
         } else if (mEnumerateCallback != null) {
             mEnumerateCallback.onEnumerateError(clientErrMsgId,
-                    getErrorString(errMsgId, vendorCode));
+                    getErrorString(mContext, errMsgId, vendorCode));
         }
     }
 
@@ -934,38 +938,37 @@
     /**
      * @hide
      */
-    @Override
-    public String getErrorString(int errMsg, int vendorCode) {
+    public static String getErrorString(Context context, int errMsg, int vendorCode) {
         switch (errMsg) {
             case FINGERPRINT_ERROR_UNABLE_TO_PROCESS:
-                return mContext.getString(
+                return context.getString(
                     com.android.internal.R.string.fingerprint_error_unable_to_process);
             case FINGERPRINT_ERROR_HW_UNAVAILABLE:
-                return mContext.getString(
+                return context.getString(
                     com.android.internal.R.string.fingerprint_error_hw_not_available);
             case FINGERPRINT_ERROR_NO_SPACE:
-                return mContext.getString(
+                return context.getString(
                     com.android.internal.R.string.fingerprint_error_no_space);
             case FINGERPRINT_ERROR_TIMEOUT:
-                return mContext.getString(com.android.internal.R.string.fingerprint_error_timeout);
+                return context.getString(com.android.internal.R.string.fingerprint_error_timeout);
             case FINGERPRINT_ERROR_CANCELED:
-                return mContext.getString(com.android.internal.R.string.fingerprint_error_canceled);
+                return context.getString(com.android.internal.R.string.fingerprint_error_canceled);
             case FINGERPRINT_ERROR_LOCKOUT:
-                return mContext.getString(com.android.internal.R.string.fingerprint_error_lockout);
+                return context.getString(com.android.internal.R.string.fingerprint_error_lockout);
             case FINGERPRINT_ERROR_LOCKOUT_PERMANENT:
-                return mContext.getString(
+                return context.getString(
                         com.android.internal.R.string.fingerprint_error_lockout_permanent);
             case FINGERPRINT_ERROR_USER_CANCELED:
-                return mContext.getString(
+                return context.getString(
                         com.android.internal.R.string.fingerprint_error_user_canceled);
             case FINGERPRINT_ERROR_NO_FINGERPRINTS:
-                return mContext.getString(
+                return context.getString(
                         com.android.internal.R.string.fingerprint_error_no_fingerprints);
             case FINGERPRINT_ERROR_HW_NOT_PRESENT:
-                return mContext.getString(
+                return context.getString(
                         com.android.internal.R.string.fingerprint_error_hw_not_present);
             case FINGERPRINT_ERROR_VENDOR: {
-                    String[] msgArray = mContext.getResources().getStringArray(
+                    String[] msgArray = context.getResources().getStringArray(
                             com.android.internal.R.array.fingerprint_error_vendor);
                     if (vendorCode < msgArray.length) {
                         return msgArray[vendorCode];
@@ -979,28 +982,27 @@
     /**
      * @hide
      */
-    @Override
-    public String getAcquiredString(int acquireInfo, int vendorCode) {
+    public static String getAcquiredString(Context context, int acquireInfo, int vendorCode) {
         switch (acquireInfo) {
             case FINGERPRINT_ACQUIRED_GOOD:
                 return null;
             case FINGERPRINT_ACQUIRED_PARTIAL:
-                return mContext.getString(
+                return context.getString(
                     com.android.internal.R.string.fingerprint_acquired_partial);
             case FINGERPRINT_ACQUIRED_INSUFFICIENT:
-                return mContext.getString(
+                return context.getString(
                     com.android.internal.R.string.fingerprint_acquired_insufficient);
             case FINGERPRINT_ACQUIRED_IMAGER_DIRTY:
-                return mContext.getString(
+                return context.getString(
                     com.android.internal.R.string.fingerprint_acquired_imager_dirty);
             case FINGERPRINT_ACQUIRED_TOO_SLOW:
-                return mContext.getString(
+                return context.getString(
                     com.android.internal.R.string.fingerprint_acquired_too_slow);
             case FINGERPRINT_ACQUIRED_TOO_FAST:
-                return mContext.getString(
+                return context.getString(
                     com.android.internal.R.string.fingerprint_acquired_too_fast);
             case FINGERPRINT_ACQUIRED_VENDOR: {
-                    String[] msgArray = mContext.getResources().getStringArray(
+                    String[] msgArray = context.getResources().getStringArray(
                             com.android.internal.R.array.fingerprint_acquired_vendor);
                     if (vendorCode < msgArray.length) {
                         return msgArray[vendorCode];
@@ -1011,14 +1013,6 @@
         return null;
     }
 
-    /**
-     * @hide
-     */
-    @Override
-    public int getType() {
-        return TYPE_FINGERPRINT;
-    }
-
     private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
 
         @Override // binder call
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 2b2c0b7..2662a11 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -17,7 +17,7 @@
 
 import android.os.Bundle;
 import android.hardware.biometrics.IBiometricPromptReceiver;
-import android.hardware.biometrics.IBiometricPromptServiceReceiver;
+import android.hardware.biometrics.IBiometricServiceReceiver;
 import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
 import android.hardware.fingerprint.IFingerprintClientActiveCallback;
 import android.hardware.fingerprint.IFingerprintServiceReceiver;
@@ -40,7 +40,7 @@
     // called from BiometricPromptService. The additional uid, pid, userId arguments should be
     // determined by BiometricPromptService.
     void authenticateFromService(IBinder token, long sessionId, int userId,
-            IBiometricPromptServiceReceiver receiver, int flags, String opPackageName,
+            IBiometricServiceReceiver receiver, int flags, String opPackageName,
             in Bundle bundle, IBiometricPromptReceiver dialogReceiver,
             int callingUid, int callingPid, int callingUserId);
 
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 6ca5f0c..bfb7c58 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -25,6 +25,7 @@
 import android.content.Context;
 import android.media.AudioAttributes;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -65,7 +66,7 @@
 
     private static InputManager sInstance;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final IInputManager mIm;
 
     // Guarded by mInputDevicesLock
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index ae0855a..4111941 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -32,6 +32,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.hardware.usb.gadget.V1_0.GadgetFunction;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
@@ -385,7 +386,7 @@
     /**
      * {@hide}
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public UsbManager(Context context, IUsbManager service) {
         mContext = context;
         mService = service;
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 34fa5b6..ae12f93 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -85,6 +85,7 @@
 import com.android.internal.inputmethod.IInputContentUriToken;
 import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
 import com.android.internal.inputmethod.InputMethodPrivilegedOperations;
+import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -409,14 +410,6 @@
     @GuardedBy("mLock")
     private boolean mNotifyUserActionSent;
 
-    /**
-     * {@code true} when the previous IME had non-empty inset at the bottom of the screen and we
-     * have not shown our own window yet.  In this situation, the previous inset continues to be
-     * shown as an empty region until it is explicitly updated. Basically we can trigger the update
-     * by calling 1) {@code mWindow.show()} or 2) {@link #clearInsetOfPreviousIme()}.
-     */
-    boolean mShouldClearInsetOfPreviousIme;
-
     @UnsupportedAppUsage
     final Insets mTmpInsets = new Insets();
     final int[] mTmpLocation = new int[2];
@@ -465,7 +458,7 @@
         public final void initializeInternal(IBinder token, int displayId,
                 IInputMethodPrivilegedOperations privilegedOperations) {
             mPrivOps.set(privilegedOperations);
-            mImm.registerInputMethodPrivOps(token, mPrivOps);
+            InputMethodPrivilegedOperationsRegistry.put(token, mPrivOps);
             updateInputMethodDisplay(displayId);
             attachToken(token);
         }
@@ -580,7 +573,6 @@
             mShowInputFlags = 0;
             mShowInputRequested = false;
             doHideWindow();
-            clearInsetOfPreviousIme();
             if (resultReceiver != null) {
                 resultReceiver.send(wasVis != isInputViewShown()
                         ? InputMethodManager.RESULT_HIDDEN
@@ -600,7 +592,6 @@
             if (dispatchOnShowInputRequested(flags, false)) {
                 showWindow(true);
             }
-            clearInsetOfPreviousIme();
             // If user uses hard keyboard, IME button should always be shown.
             setImeWindowStatus(mapToImeWindowStatus(isInputViewShown()), mBackDisposition);
 
@@ -945,9 +936,6 @@
         super.onCreate();
         mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
         mSettingsObserver = SettingsObserver.createAndRegister(this);
-        // If the previous IME has occupied non-empty inset in the screen, we need to decide whether
-        // we continue to use the same size of the inset or update it
-        mShouldClearInsetOfPreviousIme = (mImm.getInputMethodWindowVisibleHeight() > 0);
         // TODO(b/111364446) Need to address context lifecycle issue if need to re-create
         // for update resources & configuration correctly when show soft input
         // in non-default display.
@@ -1031,7 +1019,7 @@
         if (mToken != null) {
             // This is completely optional, but allows us to show more explicit error messages
             // when IME developers are doing something unsupported.
-            mImm.unregisterInputMethodPrivOps(mToken);
+            InputMethodPrivilegedOperationsRegistry.remove(mToken);
         }
     }
 
@@ -1881,9 +1869,6 @@
             if (DEBUG) Log.v(TAG, "showWindow: showing!");
             onWindowShown();
             mWindow.show();
-            // Put here rather than in onWindowShown() in case people forget to call
-            // super.onWindowShown().
-            mShouldClearInsetOfPreviousIme = false;
         }
     }
 
@@ -1933,32 +1918,6 @@
     }
 
     /**
-     * Reset the inset occupied the previous IME when and only when
-     * {@link #mShouldClearInsetOfPreviousIme} is {@code true}.
-     */
-    private void clearInsetOfPreviousIme() {
-        if (DEBUG) Log.v(TAG, "clearInsetOfPreviousIme() "
-                + " mShouldClearInsetOfPreviousIme=" + mShouldClearInsetOfPreviousIme);
-        if (!mShouldClearInsetOfPreviousIme) return;
-
-        clearLastInputMethodWindowForTransition();
-        mShouldClearInsetOfPreviousIme = false;
-    }
-
-    /**
-     * Tells the system that the IME decided to not show a window and the system no longer needs to
-     * use the previous IME's inset.
-     *
-     * <p>Caveat: {@link android.inputmethodservice.InputMethodService#clearInsetOfPreviousIme()}
-     * is the only expected caller of this method.  Do not depend on this anywhere else.</p>
-     *
-     * <p>TODO: We probably need to reconsider how IME should be handled.</p>
-     */
-    private void clearLastInputMethodWindowForTransition() {
-        mPrivOps.clearLastInputMethodWindowForTransition();
-    }
-
-    /**
      * Called when a new client has bound to the input method.  This
      * may be followed by a series of {@link #onStartInput(EditorInfo, boolean)}
      * and {@link #onFinishInput()} calls as the user navigates through its
@@ -2979,7 +2938,6 @@
                 + " visibleTopInsets=" + mTmpInsets.visibleTopInsets
                 + " touchableInsets=" + mTmpInsets.touchableInsets
                 + " touchableRegion=" + mTmpInsets.touchableRegion);
-        p.println(" mShouldClearInsetOfPreviousIme=" + mShouldClearInsetOfPreviousIme);
         p.println(" mSettingsObserver=" + mSettingsObserver);
     }
 }
diff --git a/core/java/android/inputmethodservice/Keyboard.java b/core/java/android/inputmethodservice/Keyboard.java
index ec5f050..51d33b2 100644
--- a/core/java/android/inputmethodservice/Keyboard.java
+++ b/core/java/android/inputmethodservice/Keyboard.java
@@ -25,6 +25,7 @@
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.TypedValue;
@@ -627,7 +628,7 @@
         rows.add(row);
     }
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     final void resize(int newWidth, int newHeight) {
         int numRows = rows.size();
         for (int rowIndex = 0; rowIndex < numRows; ++rowIndex) {
diff --git a/core/java/android/net/ConnectionInfo.aidl b/core/java/android/net/ConnectionInfo.aidl
new file mode 100644
index 0000000..07faf8b
--- /dev/null
+++ b/core/java/android/net/ConnectionInfo.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright (C) 2018 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.net;
+
+parcelable ConnectionInfo;
diff --git a/core/java/android/net/ConnectionInfo.java b/core/java/android/net/ConnectionInfo.java
new file mode 100644
index 0000000..58d0e05
--- /dev/null
+++ b/core/java/android/net/ConnectionInfo.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+
+/**
+ * Describe a network connection including local and remote address/port of a connection and the
+ * transport protocol.
+ *
+ * @hide
+ */
+public final class ConnectionInfo implements Parcelable {
+    public final int protocol;
+    public final InetSocketAddress local;
+    public final InetSocketAddress remote;
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public ConnectionInfo(int protocol, InetSocketAddress local, InetSocketAddress remote) {
+        this.protocol = protocol;
+        this.local = local;
+        this.remote = remote;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(protocol);
+        out.writeByteArray(local.getAddress().getAddress());
+        out.writeInt(local.getPort());
+        out.writeByteArray(remote.getAddress().getAddress());
+        out.writeInt(remote.getPort());
+    }
+
+    public static final Creator<ConnectionInfo> CREATOR = new Creator<ConnectionInfo>() {
+        public ConnectionInfo createFromParcel(Parcel in) {
+            int protocol = in.readInt();
+            InetAddress localAddress;
+            try {
+                localAddress = InetAddress.getByAddress(in.createByteArray());
+            } catch (UnknownHostException e) {
+                throw new IllegalArgumentException("Invalid InetAddress");
+            }
+            int localPort = in.readInt();
+            InetAddress remoteAddress;
+            try {
+                remoteAddress = InetAddress.getByAddress(in.createByteArray());
+            } catch (UnknownHostException e) {
+                throw new IllegalArgumentException("Invalid InetAddress");
+            }
+            int remotePort = in.readInt();
+            InetSocketAddress local = new InetSocketAddress(localAddress, localPort);
+            InetSocketAddress remote = new InetSocketAddress(remoteAddress, remotePort);
+            return new ConnectionInfo(protocol, local, remote);
+        }
+
+        public ConnectionInfo[] newArray(int size) {
+            return new ConnectionInfo[size];
+        }
+    };
+}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index ce18796..f2e9078 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -59,6 +59,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.net.InetAddress;
+import java.net.InetSocketAddress;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -3930,4 +3931,26 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Returns the {@code uid} of the owner of a network connection.
+     *
+     * @param protocol The protocol of the connection. Only {@code IPPROTO_TCP} and
+     * {@code IPPROTO_UDP} currently supported.
+     * @param local The local {@link InetSocketAddress} of a connection.
+     * @param remote The remote {@link InetSocketAddress} of a connection.
+     *
+     * @return {@code uid} if the connection is found and the app has permission to observe it
+     * (e.g., if it is associated with the calling VPN app's tunnel) or
+     * {@link android.os.Process#INVALID_UID} if the connection is not found.
+     */
+    public int getConnectionOwnerUid(int protocol, InetSocketAddress local,
+                                     InetSocketAddress remote) {
+        ConnectionInfo connectionInfo = new ConnectionInfo(protocol, local, remote);
+        try {
+            return mService.getConnectionOwnerUid(connectionInfo);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index ce95b60..e7d441d 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -17,6 +17,7 @@
 package android.net;
 
 import android.app.PendingIntent;
+import android.net.ConnectionInfo;
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkCapabilities;
@@ -182,4 +183,6 @@
     String getCaptivePortalServerUrl();
 
     byte[] getNetworkWatchlistConfigHash();
+
+    int getConnectionOwnerUid(in ConnectionInfo connectionInfo);
 }
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index fd1e5f2..12b6f9e 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -21,6 +21,7 @@
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.net.ConnectivityManager.NetworkCallback;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.ArraySet;
@@ -904,7 +905,7 @@
      *         specifier. See {@link #setNetworkSpecifier}.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public NetworkSpecifier getNetworkSpecifier() {
         return mNetworkSpecifier;
     }
diff --git a/core/java/android/net/NetworkFactory.java b/core/java/android/net/NetworkFactory.java
index 010d72f..9c836c3 100644
--- a/core/java/android/net/NetworkFactory.java
+++ b/core/java/android/net/NetworkFactory.java
@@ -211,7 +211,7 @@
      * Called for every request every time a new NetworkRequest is seen
      * and whenever the filterScore or filterNetworkCapabilities change.
      *
-     * acceptRequest can be overriden to provide complex filter behavior
+     * acceptRequest can be overridden to provide complex filter behavior
      * for the incoming requests
      *
      * For output, this class will call {@link #needNetworkFor} and
diff --git a/core/java/android/net/NetworkSpecifier.java b/core/java/android/net/NetworkSpecifier.java
index 9ce2a5b..be2f955 100644
--- a/core/java/android/net/NetworkSpecifier.java
+++ b/core/java/android/net/NetworkSpecifier.java
@@ -35,7 +35,7 @@
     public abstract boolean satisfiedBy(NetworkSpecifier other);
 
     /**
-     * Optional method which can be overriden by concrete implementations of NetworkSpecifier to
+     * Optional method which can be overridden by concrete implementations of NetworkSpecifier to
      * check a self-reported UID. A concrete implementation may contain a UID which would be self-
      * reported by the caller (since NetworkSpecifier implementations should be non-mutable). This
      * function is called by ConnectivityService and is passed the actual UID of the caller -
diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java
index c545ee2..97fb3fb 100644
--- a/core/java/android/net/NetworkState.java
+++ b/core/java/android/net/NetworkState.java
@@ -17,6 +17,7 @@
 package android.net;
 
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Slog;
@@ -34,7 +35,7 @@
     public final NetworkInfo networkInfo;
     public final LinkProperties linkProperties;
     public final NetworkCapabilities networkCapabilities;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public final Network network;
     public final String subscriberId;
     public final String networkId;
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 31494d9..abc1cac 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -17,6 +17,7 @@
 package android.net;
 
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.os.SystemProperties;
 import android.util.Log;
 
@@ -87,7 +88,7 @@
  * requires root access.
  */
 public class SSLCertificateSocketFactory extends SSLSocketFactory {
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private static final String TAG = "SSLCertificateSocketFactory";
 
     @UnsupportedAppUsage
@@ -384,7 +385,7 @@
      * @throws IllegalArgumentException if the socket was not created by this factory.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public byte[] getAlpnSelectedProtocol(Socket socket) {
         return castToOpenSSLSocket(socket).getAlpnSelectedProtocol();
     }
@@ -410,7 +411,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public void setChannelIdPrivateKey(PrivateKey privateKey) {
         mChannelIdPrivateKey = privateKey;
     }
diff --git a/core/java/android/nfc/NfcManager.java b/core/java/android/nfc/NfcManager.java
index 71199c9..030066e 100644
--- a/core/java/android/nfc/NfcManager.java
+++ b/core/java/android/nfc/NfcManager.java
@@ -19,6 +19,7 @@
 import android.annotation.SystemService;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
+import android.os.Build;
 
 /**
  * High level manager used to obtain an instance of an {@link NfcAdapter}.
@@ -45,7 +46,7 @@
     /**
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public NfcManager(Context context) {
         NfcAdapter adapter;
         context = context.getApplicationContext();
diff --git a/core/java/android/nfc/tech/MifareClassic.java b/core/java/android/nfc/tech/MifareClassic.java
index 02819a6..080e058 100644
--- a/core/java/android/nfc/tech/MifareClassic.java
+++ b/core/java/android/nfc/tech/MifareClassic.java
@@ -38,7 +38,7 @@
  * <li>MIFARE Classic Mini are 320 bytes ({@link #SIZE_MINI}), with 5 sectors each of 4 blocks.
  * <li>MIFARE Classic 1k are 1024 bytes ({@link #SIZE_1K}), with 16 sectors each of 4 blocks.
  * <li>MIFARE Classic 2k are 2048 bytes ({@link #SIZE_2K}), with 32 sectors each of 4 blocks.
- * <li>MIFARE Classic 4k} are 4096 bytes ({@link #SIZE_4K}). The first 32 sectors contain 4 blocks
+ * <li>MIFARE Classic 4k are 4096 bytes ({@link #SIZE_4K}). The first 32 sectors contain 4 blocks
  * and the last 8 sectors contain 16 blocks.
  * </ul>
  *
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index b9d9007..f947b5e 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -773,6 +773,7 @@
             if (tracingEnabled) {
                 Trace.traceBegin(Trace.TRACE_TAG_ALWAYS, getClass().getName() + ":" + code);
             }
+            ThreadLocalWorkSourceUid.set(Binder.getCallingUid());
             res = onTransact(code, data, reply, flags);
         } catch (RemoteException|RuntimeException e) {
             if (observer != null) {
@@ -793,6 +794,7 @@
             }
             res = true;
         } finally {
+            ThreadLocalWorkSourceUid.clear();
             if (tracingEnabled) {
                 Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
             }
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 347f60f..3c43fd18 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
@@ -165,6 +166,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static File getOemDirectory() {
         return DIR_OEM_ROOT;
     }
@@ -175,6 +177,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static File getOdmDirectory() {
         return DIR_ODM_ROOT;
     }
@@ -184,6 +187,7 @@
      * software that should persist across simple reflashing of the "system" partition.
      * @hide
      */
+    @SystemApi
     public static File getVendorDirectory() {
         return DIR_VENDOR_ROOT;
     }
@@ -194,6 +198,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static File getProductDirectory() {
         return DIR_PRODUCT_ROOT;
     }
@@ -204,6 +209,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static File getProductServicesDirectory() {
         return DIR_PRODUCT_SERVICES_ROOT;
     }
@@ -1063,7 +1069,6 @@
         return cur;
     }
 
-
     /**
      * If the given path exists on emulated external storage, return the
      * translated backing path hosted on internal storage. This bypasses any
@@ -1074,8 +1079,10 @@
      * must hold {@link android.Manifest.permission#WRITE_MEDIA_STORAGE}
      * permission.
      *
+     * @deprecated disabled now that FUSE has been replaced by sdcardfs
      * @hide
      */
+    @Deprecated
     public static File maybeTranslateEmulatedPathToInternal(File path) {
         return StorageManager.maybeTranslateEmulatedPathToInternal(path);
     }
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 1c8029c..a9cb0d9 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -16,6 +16,18 @@
 
 package android.os;
 
+import static android.os.ParcelFileDescriptor.MODE_APPEND;
+import static android.os.ParcelFileDescriptor.MODE_CREATE;
+import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
+import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
+import static android.os.ParcelFileDescriptor.MODE_TRUNCATE;
+import static android.os.ParcelFileDescriptor.MODE_WRITE_ONLY;
+import static android.system.OsConstants.O_APPEND;
+import static android.system.OsConstants.O_CREAT;
+import static android.system.OsConstants.O_RDONLY;
+import static android.system.OsConstants.O_RDWR;
+import static android.system.OsConstants.O_TRUNC;
+import static android.system.OsConstants.O_WRONLY;
 import static android.system.OsConstants.SPLICE_F_MORE;
 import static android.system.OsConstants.SPLICE_F_MOVE;
 import static android.system.OsConstants.S_ISFIFO;
@@ -1061,8 +1073,13 @@
                 mimeTypeFromExt = ContentResolver.MIME_TYPE_DEFAULT;
             }
 
-            final String extFromMimeType = MimeTypeMap.getSingleton().getExtensionFromMimeType(
-                    mimeType);
+            final String extFromMimeType;
+            if (ContentResolver.MIME_TYPE_DEFAULT.equals(mimeType)) {
+                extFromMimeType = null;
+            } else {
+                extFromMimeType = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType);
+            }
+
             if (Objects.equals(mimeType, mimeTypeFromExt) || Objects.equals(ext, extFromMimeType)) {
                 // Extension maps back to requested MIME type; allow it
             } else {
@@ -1180,6 +1197,96 @@
     }
 
     /** {@hide} */
+    public static int translateModeStringToPosix(String mode) {
+        int res = 0;
+        if (mode.startsWith("rw")) {
+            res |= O_RDWR | O_CREAT;
+        } else if (mode.startsWith("w")) {
+            res |= O_WRONLY | O_CREAT;
+        } else if (mode.startsWith("r")) {
+            res |= O_RDONLY;
+        } else {
+            throw new IllegalArgumentException("Bad mode: " + mode);
+        }
+        if (mode.indexOf('t') != -1) {
+            res |= O_TRUNC;
+        }
+        if (mode.indexOf('a') != -1) {
+            res |= O_APPEND;
+        }
+        return res;
+    }
+
+    /** {@hide} */
+    public static String translateModePosixToString(int mode) {
+        String res = "";
+        if ((mode & O_RDWR) == O_RDWR) {
+            res += "rw";
+        } else if ((mode & O_WRONLY) == O_WRONLY) {
+            res += "w";
+        } else if ((mode & O_RDONLY) == O_RDONLY) {
+            res += "r";
+        } else {
+            throw new IllegalArgumentException("Bad mode: " + mode);
+        }
+        if ((mode & O_TRUNC) == O_TRUNC) {
+            res += "t";
+        }
+        if ((mode & O_APPEND) == O_APPEND) {
+            res += "a";
+        }
+        return res;
+    }
+
+    /** {@hide} */
+    public static int translateModePosixToPfd(int mode) {
+        int res = 0;
+        if ((mode & O_RDWR) == O_RDWR) {
+            res |= MODE_READ_WRITE;
+        } else if ((mode & O_WRONLY) == O_WRONLY) {
+            res |= MODE_WRITE_ONLY;
+        } else if ((mode & O_RDONLY) == O_RDONLY) {
+            res |= MODE_READ_ONLY;
+        } else {
+            throw new IllegalArgumentException("Bad mode: " + mode);
+        }
+        if ((mode & O_CREAT) == O_CREAT) {
+            res |= MODE_CREATE;
+        }
+        if ((mode & O_TRUNC) == O_TRUNC) {
+            res |= MODE_TRUNCATE;
+        }
+        if ((mode & O_APPEND) == O_APPEND) {
+            res |= MODE_APPEND;
+        }
+        return res;
+    }
+
+    /** {@hide} */
+    public static int translateModePfdToPosix(int mode) {
+        int res = 0;
+        if ((mode & MODE_READ_WRITE) == MODE_READ_WRITE) {
+            res |= O_RDWR;
+        } else if ((mode & MODE_WRITE_ONLY) == MODE_WRITE_ONLY) {
+            res |= O_WRONLY;
+        } else if ((mode & MODE_READ_ONLY) == MODE_READ_ONLY) {
+            res |= O_RDONLY;
+        } else {
+            throw new IllegalArgumentException("Bad mode: " + mode);
+        }
+        if ((mode & MODE_CREATE) == MODE_CREATE) {
+            res |= O_CREAT;
+        }
+        if ((mode & MODE_TRUNCATE) == MODE_TRUNCATE) {
+            res |= O_TRUNC;
+        }
+        if ((mode & MODE_APPEND) == MODE_APPEND) {
+            res |= O_APPEND;
+        }
+        return res;
+    }
+
+    /** {@hide} */
     @VisibleForTesting
     public static class MemoryPipe extends Thread implements AutoCloseable {
         private final FileDescriptor[] pipe;
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index e03af9d..f3a9a50 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -739,6 +739,8 @@
 
     private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
         msg.target = this;
+        msg.workSourceUid = ThreadLocalWorkSourceUid.get();
+
         if (mAsynchronous) {
             msg.setAsynchronous(true);
         }
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index ded3a19..5b8abab 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -205,6 +205,7 @@
                 token = observer.messageDispatchStarting();
             }
             try {
+                ThreadLocalWorkSourceUid.set(msg.workSourceUid);
                 msg.target.dispatchMessage(msg);
                 if (observer != null) {
                     observer.messageDispatched(token, msg);
@@ -216,6 +217,7 @@
                 }
                 throw exception;
             } finally {
+                ThreadLocalWorkSourceUid.clear();
                 if (traceTag != 0) {
                     Trace.traceEnd(traceTag);
                 }
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index 455d8ed..cd3f301 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -16,7 +16,6 @@
 
 package android.os;
 
-import android.os.MessageProto;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 
@@ -74,11 +73,25 @@
     public Messenger replyTo;
 
     /**
+     * Indicates that the uid is not set;
+     *
+     * @hide Only for use within the system server.
+     */
+    public static final int UID_NONE = -1;
+
+    /**
      * Optional field indicating the uid that sent the message.  This is
      * only valid for messages posted by a {@link Messenger}; otherwise,
      * it will be -1.
      */
-    public int sendingUid = -1;
+    public int sendingUid = UID_NONE;
+
+    /**
+     * Optional field indicating the uid that caused this message to be enqueued.
+     *
+     * @hide Only for use within the system server.
+     */
+    public int workSourceUid = UID_NONE;
 
     /** If set message is in use.
      * This flag is set when the message is enqueued and remains set while it
@@ -151,6 +164,7 @@
         m.obj = orig.obj;
         m.replyTo = orig.replyTo;
         m.sendingUid = orig.sendingUid;
+        m.workSourceUid = orig.workSourceUid;
         if (orig.data != null) {
             m.data = new Bundle(orig.data);
         }
@@ -301,7 +315,8 @@
         arg2 = 0;
         obj = null;
         replyTo = null;
-        sendingUid = -1;
+        sendingUid = UID_NONE;
+        workSourceUid = UID_NONE;
         when = 0;
         target = null;
         callback = null;
@@ -329,6 +344,7 @@
         this.obj = o.obj;
         this.replyTo = o.replyTo;
         this.sendingUid = o.sendingUid;
+        this.workSourceUid = o.workSourceUid;
 
         if (o.data != null) {
             this.data = (Bundle) o.data.clone();
@@ -612,6 +628,7 @@
         dest.writeBundle(data);
         Messenger.writeMessengerOrNullToParcel(replyTo, dest);
         dest.writeInt(sendingUid);
+        dest.writeInt(workSourceUid);
     }
 
     private void readFromParcel(Parcel source) {
@@ -625,5 +642,6 @@
         data = source.readBundle();
         replyTo = Messenger.readMessengerOrNullFromParcel(source);
         sendingUid = source.readInt();
+        workSourceUid = source.readInt();
     }
 }
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index c9edc53..a54c589 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -559,28 +559,7 @@
      * @throws IllegalArgumentException if the given string does not match a known file mode.
      */
     public static int parseMode(String mode) {
-        final int modeBits;
-        if ("r".equals(mode)) {
-            modeBits = ParcelFileDescriptor.MODE_READ_ONLY;
-        } else if ("w".equals(mode) || "wt".equals(mode)) {
-            modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
-                    | ParcelFileDescriptor.MODE_CREATE
-                    | ParcelFileDescriptor.MODE_TRUNCATE;
-        } else if ("wa".equals(mode)) {
-            modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
-                    | ParcelFileDescriptor.MODE_CREATE
-                    | ParcelFileDescriptor.MODE_APPEND;
-        } else if ("rw".equals(mode)) {
-            modeBits = ParcelFileDescriptor.MODE_READ_WRITE
-                    | ParcelFileDescriptor.MODE_CREATE;
-        } else if ("rwt".equals(mode)) {
-            modeBits = ParcelFileDescriptor.MODE_READ_WRITE
-                    | ParcelFileDescriptor.MODE_CREATE
-                    | ParcelFileDescriptor.MODE_TRUNCATE;
-        } else {
-            throw new IllegalArgumentException("Bad mode '" + mode + "'");
-        }
-        return modeBits;
+        return FileUtils.translateModePosixToPfd(FileUtils.translateModeStringToPosix(mode));
     }
 
     /**
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 5cd2ffc..6fab3c4 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -42,6 +42,11 @@
     public static final String SECONDARY_ZYGOTE_SOCKET = "zygote_secondary";
 
     /**
+     * An invalid UID value.
+     */
+    public static final int INVALID_UID = -1;
+
+    /**
      * Defines the root UID.
      * @hide
      */
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 3e8e885..8492b0c 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -36,16 +36,12 @@
 import android.view.Display;
 import android.view.WindowManager;
 
-import com.android.internal.logging.MetricsLogger;
-
 import libcore.io.Streams;
 
-import java.io.BufferedReader;
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
-import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStream;
@@ -97,7 +93,7 @@
     /** Used to communicate with recovery.  See bootable/recovery/recovery.cpp. */
     private static final File RECOVERY_DIR = new File("/cache/recovery");
     private static final File LOG_FILE = new File(RECOVERY_DIR, "log");
-    private static final File LAST_INSTALL_FILE = new File(RECOVERY_DIR, "last_install");
+    private static final String LAST_INSTALL_PATH = "last_install";
     private static final String LAST_PREFIX = "last_";
     private static final String ACTION_EUICC_FACTORY_RESET =
             "com.android.internal.action.EUICC_FACTORY_RESET";
@@ -935,116 +931,6 @@
         throw new IOException("Reboot failed (no permissions?)");
     }
 
-    // Read last_install; then report time (in seconds) and I/O (in MiB) for
-    // this update to tron.
-    // Only report on the reboots immediately after an OTA update.
-    private static void parseLastInstallLog(Context context) {
-        try (BufferedReader in = new BufferedReader(new FileReader(LAST_INSTALL_FILE))) {
-            String line = null;
-            int bytesWrittenInMiB = -1, bytesStashedInMiB = -1;
-            int timeTotal = -1;
-            int uncryptTime = -1;
-            int sourceVersion = -1;
-            int temperatureStart = -1;
-            int temperatureEnd = -1;
-            int temperatureMax = -1;
-            int errorCode = -1;
-            int causeCode = -1;
-
-            while ((line = in.readLine()) != null) {
-                // Here is an example of lines in last_install:
-                // ...
-                // time_total: 101
-                // bytes_written_vendor: 51074
-                // bytes_stashed_vendor: 200
-                int numIndex = line.indexOf(':');
-                if (numIndex == -1 || numIndex + 1 >= line.length()) {
-                    continue;
-                }
-                String numString = line.substring(numIndex + 1).trim();
-                long parsedNum;
-                try {
-                    parsedNum = Long.parseLong(numString);
-                } catch (NumberFormatException ignored) {
-                    Log.e(TAG, "Failed to parse numbers in " + line);
-                    continue;
-                }
-
-                final int MiB = 1024 * 1024;
-                int scaled;
-                try {
-                    if (line.startsWith("bytes")) {
-                        scaled = Math.toIntExact(parsedNum / MiB);
-                    } else {
-                        scaled = Math.toIntExact(parsedNum);
-                    }
-                } catch (ArithmeticException ignored) {
-                    Log.e(TAG, "Number overflows in " + line);
-                    continue;
-                }
-
-                if (line.startsWith("time")) {
-                    timeTotal = scaled;
-                } else if (line.startsWith("uncrypt_time")) {
-                    uncryptTime = scaled;
-                } else if (line.startsWith("source_build")) {
-                    sourceVersion = scaled;
-                } else if (line.startsWith("bytes_written")) {
-                    bytesWrittenInMiB = (bytesWrittenInMiB == -1) ? scaled :
-                            bytesWrittenInMiB + scaled;
-                } else if (line.startsWith("bytes_stashed")) {
-                    bytesStashedInMiB = (bytesStashedInMiB == -1) ? scaled :
-                            bytesStashedInMiB + scaled;
-                } else if (line.startsWith("temperature_start")) {
-                    temperatureStart = scaled;
-                } else if (line.startsWith("temperature_end")) {
-                    temperatureEnd = scaled;
-                } else if (line.startsWith("temperature_max")) {
-                    temperatureMax = scaled;
-                } else if (line.startsWith("error")) {
-                    errorCode = scaled;
-                } else if (line.startsWith("cause")) {
-                    causeCode = scaled;
-                }
-            }
-
-            // Don't report data to tron if corresponding entry isn't found in last_install.
-            if (timeTotal != -1) {
-                MetricsLogger.histogram(context, "ota_time_total", timeTotal);
-            }
-            if (uncryptTime != -1) {
-                MetricsLogger.histogram(context, "ota_uncrypt_time", uncryptTime);
-            }
-            if (sourceVersion != -1) {
-                MetricsLogger.histogram(context, "ota_source_version", sourceVersion);
-            }
-            if (bytesWrittenInMiB != -1) {
-                MetricsLogger.histogram(context, "ota_written_in_MiBs", bytesWrittenInMiB);
-            }
-            if (bytesStashedInMiB != -1) {
-                MetricsLogger.histogram(context, "ota_stashed_in_MiBs", bytesStashedInMiB);
-            }
-            if (temperatureStart != -1) {
-                MetricsLogger.histogram(context, "ota_temperature_start", temperatureStart);
-            }
-            if (temperatureEnd != -1) {
-                MetricsLogger.histogram(context, "ota_temperature_end", temperatureEnd);
-            }
-            if (temperatureMax != -1) {
-                MetricsLogger.histogram(context, "ota_temperature_max", temperatureMax);
-            }
-            if (errorCode != -1) {
-                MetricsLogger.histogram(context, "ota_non_ab_error_code", errorCode);
-            }
-            if (causeCode != -1) {
-                MetricsLogger.histogram(context, "ota_non_ab_cause_code", causeCode);
-            }
-
-        } catch (IOException e) {
-            Log.e(TAG, "Failed to read lines in last_install", e);
-        }
-    }
-
     /**
      * Called after booting to process and remove recovery-related files.
      * @return the log file from recovery, or null if none was found.
@@ -1062,9 +948,6 @@
             Log.e(TAG, "Error reading recovery log", e);
         }
 
-        if (log != null) {
-            parseLastInstallLog(context);
-        }
 
         // Only remove the OTA package if it's partially processed (uncrypt'd).
         boolean reservePackage = BLOCK_MAP_FILE.exists();
@@ -1095,7 +978,8 @@
         // GmsCore to avoid re-downloading everything again.
         String[] names = RECOVERY_DIR.list();
         for (int i = 0; names != null && i < names.length; i++) {
-            if (names[i].startsWith(LAST_PREFIX)) continue;
+            // Do not remove the last_install file since the recovery-persist takes care of it.
+            if (names[i].startsWith(LAST_PREFIX) || names[i].equals(LAST_INSTALL_PATH)) continue;
             if (reservePackage && names[i].equals(BLOCK_MAP_FILE.getName())) continue;
             if (reservePackage && names[i].equals(UNCRYPT_PACKAGE_FILE.getName())) continue;
 
diff --git a/core/java/android/os/StatsLogEventWrapper.java b/core/java/android/os/StatsLogEventWrapper.java
index b13bcac..051ab75 100644
--- a/core/java/android/os/StatsLogEventWrapper.java
+++ b/core/java/android/os/StatsLogEventWrapper.java
@@ -15,8 +15,10 @@
  */
 package android.os;
 
-import java.io.ByteArrayOutputStream;
-import java.nio.charset.StandardCharsets;
+import android.util.Slog;
+
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Wrapper class for sending data from Android OS to StatsD.
@@ -24,39 +26,28 @@
  * @hide
  */
 public final class StatsLogEventWrapper implements Parcelable {
-    private ByteArrayOutputStream mStorage = new ByteArrayOutputStream();
+    static final boolean DEBUG = false;
+    static final String TAG = "StatsLogEventWrapper";
 
-    // Below are constants copied from log/log.h
-    private static final int EVENT_TYPE_INT = 0;  /* int32_t */
-    private static final int EVENT_TYPE_LONG = 1; /* int64_t */
-    private static final int EVENT_TYPE_STRING = 2;
-    private static final int EVENT_TYPE_LIST = 3;
-    private static final int EVENT_TYPE_FLOAT = 4;
+    // Keep in sync with FieldValue.h enums
+    private static final int EVENT_TYPE_UNKNOWN = 0;
+    private static final int EVENT_TYPE_INT = 1; /* int32_t */
+    private static final int EVENT_TYPE_LONG = 2; /* int64_t */
+    private static final int EVENT_TYPE_FLOAT = 3;
+    private static final int EVENT_TYPE_DOUBLE = 4;
+    private static final int EVENT_TYPE_STRING = 5;
+    private static final int EVENT_TYPE_STORAGE = 6;
 
-    // Keep this in sync with system/core/logcat/event.logtags
-    private static final int STATS_BUFFER_TAG_ID = 1937006964;
-    /**
-     * Creates a log_event that is binary-encoded as implemented in
-     * system/core/liblog/log_event_list.c; this allows us to use the same parsing logic in statsd
-     * for pushed and pulled data. The write* methods must be called in the same order as their
-     * field number. There is no checking that the correct number of write* methods is called.
-     * We also write an END_LIST character before beginning to write to parcel, but this END_LIST
-     * may be unnecessary.
-     *
-     * @param tag    The integer representing the tag for this event.
-     * @param fields The number of fields specified in this event.
-     */
-    public StatsLogEventWrapper(long elapsedNanos, int tag, int fields) {
-        // Write four bytes from tag, starting with least-significant bit.
-        // For pulled data, this tag number is not really used. We use the same tag number as
-        // pushed ones to be consistent.
-        write4Bytes(STATS_BUFFER_TAG_ID);
-        mStorage.write(EVENT_TYPE_LIST); // This is required to start the log entry.
-        mStorage.write(fields + 2); // Indicate number of elements in this list. +1 for the tag
-        // The first element is the elapsed realtime.
-        writeLong(elapsedNanos);
-        // The second element is the real atom tag number
-        writeInt(tag);
+    List<Integer> mTypes = new ArrayList<>();
+    List<Object> mValues = new ArrayList<>();
+    int mTag;
+    long mElapsedTimeNs;
+    long mWallClockTimeNs;
+
+    public StatsLogEventWrapper(int tag, long elapsedTimeNs, long wallClockTimeNs) {
+        this.mTag = tag;
+        this.mElapsedTimeNs = elapsedTimeNs;
+        this.mWallClockTimeNs = wallClockTimeNs;
     }
 
     /**
@@ -79,69 +70,80 @@
                 }
             };
 
-    private void write4Bytes(int val) {
-        mStorage.write(val);
-        mStorage.write(val >>> 8);
-        mStorage.write(val >>> 16);
-        mStorage.write(val >>> 24);
-    }
-
-    private void write8Bytes(long val) {
-        write4Bytes((int) (val & 0xFFFFFFFF)); // keep the lowe 32-bits
-        write4Bytes((int) (val >>> 32)); // Write the high 32-bits.
-    }
-
-    /**
-     * Adds 32-bit integer to output.
-     */
     public void writeInt(int val) {
-        mStorage.write(EVENT_TYPE_INT);
-        write4Bytes(val);
+        mTypes.add(EVENT_TYPE_INT);
+        mValues.add(val);
     }
 
-    /**
-     * Adds 64-bit long to output.
-     */
     public void writeLong(long val) {
-        mStorage.write(EVENT_TYPE_LONG);
-        write8Bytes(val);
+        mTypes.add(EVENT_TYPE_LONG);
+        mValues.add(val);
     }
 
     /**
-     * Adds a 4-byte floating point value to output.
-     */
-    public void writeFloat(float val) {
-        int v = Float.floatToIntBits(val);
-        mStorage.write(EVENT_TYPE_FLOAT);
-        write4Bytes(v);
-    }
-
-    /**
-     * Adds a string to the output.
+     * Write a string value.
      */
     public void writeString(String val) {
-        mStorage.write(EVENT_TYPE_STRING);
-        write4Bytes(val.length());
-        byte[] bytes = val.getBytes(StandardCharsets.UTF_8);
-        mStorage.write(bytes, 0, bytes.length);
+        mTypes.add(EVENT_TYPE_STRING);
+        // use empty string for null
+        mValues.add(val == null ? "" : val);
+    }
+
+    public void writeFloat(float val) {
+        mTypes.add(EVENT_TYPE_FLOAT);
+        mValues.add(val);
     }
 
     /**
-     * Adds a boolean by adding either a 1 or 0 to the output.
+     * Write a storage value.
      */
+    public void writeStorage(byte[] val) {
+        mTypes.add(EVENT_TYPE_STORAGE);
+        mValues.add(val);
+    }
+
     public void writeBoolean(boolean val) {
-        int toWrite = val ? 1 : 0;
-        mStorage.write(EVENT_TYPE_INT);
-        write4Bytes(toWrite);
+        mTypes.add(EVENT_TYPE_INT);
+        mValues.add(val ? 1 : 0);
     }
 
     /**
      * Writes the stored fields to a byte array. Will first write a new-line character to denote
      * END_LIST before writing contents to byte array.
      */
+
     public void writeToParcel(Parcel out, int flags) {
-        mStorage.write(10); // new-line character is same as END_LIST
-        out.writeByteArray(mStorage.toByteArray());
+        if (DEBUG) {
+            Slog.d(TAG,
+                    "Writing " + mTag + " " + mElapsedTimeNs + " " + mWallClockTimeNs + " and "
+                            + mTypes.size() + " elements.");
+        }
+        out.writeInt(mTag);
+        out.writeLong(mElapsedTimeNs);
+        out.writeLong(mWallClockTimeNs);
+        out.writeInt(mTypes.size());
+        for (int i = 0; i < mTypes.size(); i++) {
+            out.writeInt(mTypes.get(i));
+            switch (mTypes.get(i)) {
+                case EVENT_TYPE_INT:
+                    out.writeInt((int) mValues.get(i));
+                    break;
+                case EVENT_TYPE_LONG:
+                    out.writeLong((long) mValues.get(i));
+                    break;
+                case EVENT_TYPE_FLOAT:
+                    out.writeFloat((float) mValues.get(i));
+                    break;
+                case EVENT_TYPE_STRING:
+                    out.writeString((String) mValues.get(i));
+                    break;
+                case EVENT_TYPE_STORAGE:
+                    out.writeByteArray((byte[]) mValues.get(i));
+                    break;
+                default:
+                    break;
+            }
+        }
     }
 
     /**
diff --git a/core/java/android/os/ThreadLocalWorkSourceUid.java b/core/java/android/os/ThreadLocalWorkSourceUid.java
new file mode 100644
index 0000000..df1d275
--- /dev/null
+++ b/core/java/android/os/ThreadLocalWorkSourceUid.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/**
+ * @hide Only for use within system server.
+ */
+public final class ThreadLocalWorkSourceUid {
+    public static final int UID_NONE = Message.UID_NONE;
+    private static final ThreadLocal<Integer> sWorkSourceUid =
+            ThreadLocal.withInitial(() -> UID_NONE);
+
+    /** Returns the original work source uid. */
+    public static int get() {
+        return sWorkSourceUid.get();
+    }
+
+    /** Sets the original work source uid. */
+    public static void set(int uid) {
+        sWorkSourceUid.set(uid);
+    }
+
+    /** Clears the stored work source uid. */
+    public static void clear() {
+        sWorkSourceUid.set(UID_NONE);
+    }
+
+    private ThreadLocalWorkSourceUid() {
+    }
+}
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 995156a..4fe2d58 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -38,12 +38,16 @@
     public static final @UserIdInt int USER_ALL = -1;
 
     /** @hide A user handle to indicate all users on the device */
+    @SystemApi
+    @TestApi
     public static final UserHandle ALL = new UserHandle(USER_ALL);
 
     /** @hide A user id to indicate the currently active user */
     public static final @UserIdInt int USER_CURRENT = -2;
 
     /** @hide A user handle to indicate the current user of the device */
+    @SystemApi
+    @TestApi
     public static final UserHandle CURRENT = new UserHandle(USER_CURRENT);
 
     /** @hide A user id to indicate that we would like to send to the current
@@ -83,6 +87,7 @@
     public static final int USER_SERIAL_SYSTEM = 0;
 
     /** @hide A user handle to indicate the "system" user of the device */
+    @SystemApi
     @TestApi
     public static final UserHandle SYSTEM = new UserHandle(USER_SYSTEM);
 
diff --git a/core/java/android/os/health/SystemHealthManager.java b/core/java/android/os/health/SystemHealthManager.java
index f303674..71eda19 100644
--- a/core/java/android/os/health/SystemHealthManager.java
+++ b/core/java/android/os/health/SystemHealthManager.java
@@ -20,6 +20,7 @@
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.BatteryStats;
+import android.os.Build;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -65,7 +66,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public static SystemHealthManager from(Context context) {
         return (SystemHealthManager)context.getSystemService(Context.SYSTEM_HEALTH_SERVICE);
     }
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 8d5017b..50ca4ab 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1521,7 +1521,11 @@
         return SystemProperties.getBoolean(PROP_HAS_ADOPTABLE, false);
     }
 
-    /** {@hide} */
+    /**
+     * @deprecated disabled now that FUSE has been replaced by sdcardfs
+     * @hide
+     */
+    @Deprecated
     public static File maybeTranslateEmulatedPathToInternal(File path) {
         // Disabled now that FUSE has been replaced by sdcardfs
         return path;
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index deff693..5bef7ee 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Environment;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -249,7 +250,7 @@
     }
 
     /** {@hide} */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public UserHandle getOwner() {
         return mOwner;
     }
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
new file mode 100644
index 0000000..aa44eb7
--- /dev/null
+++ b/core/java/android/permission/PermissionManager.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.content.Context;
+
+import com.android.internal.annotations.Immutable;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * System level service for accessing the permission capabilities of the platform.
+ *
+ * @hide
+ */
+@SystemApi
+@SystemService(Context.PERMISSION_SERVICE)
+public final class PermissionManager {
+    /**
+     * {@link android.content.pm.PackageParser} needs access without having a {@link Context}.
+     *
+     * @hide
+     */
+    public static final SplitPermissionInfo[] SPLIT_PERMISSIONS = new SplitPermissionInfo[]{
+            // READ_EXTERNAL_STORAGE is always required when an app requests
+            // WRITE_EXTERNAL_STORAGE, because we can't have an app that has
+            // write access without read access.  The hack here with the target
+            // target SDK version ensures that this grant is always done.
+            new SplitPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
+                    new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE},
+                    android.os.Build.VERSION_CODES.CUR_DEVELOPMENT + 1),
+            new SplitPermissionInfo(android.Manifest.permission.READ_CONTACTS,
+                    new String[]{android.Manifest.permission.READ_CALL_LOG},
+                    android.os.Build.VERSION_CODES.JELLY_BEAN),
+            new SplitPermissionInfo(android.Manifest.permission.WRITE_CONTACTS,
+                    new String[]{android.Manifest.permission.WRITE_CALL_LOG},
+                    android.os.Build.VERSION_CODES.JELLY_BEAN),
+            new SplitPermissionInfo(Manifest.permission.ACCESS_FINE_LOCATION,
+                    new String[]{android.Manifest.permission.ACCESS_BACKGROUND_LOCATION},
+                    android.os.Build.VERSION_CODES.P0),
+            new SplitPermissionInfo(Manifest.permission.ACCESS_COARSE_LOCATION,
+                    new String[]{android.Manifest.permission.ACCESS_BACKGROUND_LOCATION},
+                    android.os.Build.VERSION_CODES.P0)};
+
+    private final @NonNull Context mContext;
+
+    /**
+     * Creates a new instance.
+     *
+     * @param context The current context in which to operate.
+     * @hide
+     */
+    public PermissionManager(@NonNull Context context) {
+        mContext = context;
+    }
+
+    /**
+     * Get list of permissions that have been split into more granular or dependent permissions.
+     *
+     * <p>E.g. before {@link android.os.Build.VERSION_CODES#P0} an app that was granted
+     * {@link Manifest.permission#ACCESS_COARSE_LOCATION} could access he location while it was in
+     * foreground and background. On platforms after {@link android.os.Build.VERSION_CODES#P0}
+     * the location permission only grants location access while the app is in foreground. This
+     * would break apps that target before {@link android.os.Build.VERSION_CODES#P0}. Hence whenever
+     * such an old app asks for a location permission (i.e. the
+     * {@link SplitPermissionInfo#getRootPermission()}), then the
+     * {@link Manifest.permission#ACCESS_BACKGROUND_LOCATION} permission (inside
+     * {@{@link SplitPermissionInfo#getNewPermissions}) is added.
+     *
+     * <p>Note: Regular apps do not have to worry about this. The platform and permission controller
+     * automatically add the new permissions where needed.
+     *
+     * @return All permissions that are split.
+     */
+    public @NonNull List<SplitPermissionInfo> getSplitPermissions() {
+        return Arrays.asList(SPLIT_PERMISSIONS);
+    }
+
+    /**
+     * A permission that was added in a previous API level might have split into several
+     * permissions. This object describes one such split.
+     */
+    @Immutable
+    public static final class SplitPermissionInfo {
+        private final @NonNull String mRootPerm;
+        private final @NonNull String[] mNewPerms;
+        private final int mTargetSdk;
+
+        /**
+         * Get the permission that is split.
+         */
+        public @NonNull String getRootPermission() {
+            return mRootPerm;
+        }
+
+        /**
+         * Get the permissions that are added.
+         */
+        public @NonNull String[] getNewPermissions() {
+            return mNewPerms;
+        }
+
+        /**
+         * Get the target API level when the permission was split.
+         */
+        public int getTargetSdk() {
+            return mTargetSdk;
+        }
+
+        private SplitPermissionInfo(@NonNull String rootPerm, @NonNull String[] newPerms,
+                int targetSdk) {
+            mRootPerm = rootPerm;
+            mNewPerms = newPerms;
+            mTargetSdk = targetSdk;
+        }
+    }
+}
diff --git a/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java b/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
index e0bffae..18aea03 100644
--- a/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
+++ b/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
@@ -16,8 +16,8 @@
 
 package android.permissionpresenterservice;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
@@ -74,15 +74,13 @@
     public abstract List<RuntimePermissionPresentationInfo> onGetAppPermissions(String packageName);
 
     /**
-     * Revoke the permission {@code permissionName} for app {@code packageName}
+     * Revokes the permission {@code permissionName} for app {@code packageName}
      *
      * @param packageName The package for which to revoke
      * @param permissionName The permission to revoke
-     *
-     * @hide
      */
-    @UnsupportedAppUsage
-    public abstract void onRevokeRuntimePermission(String packageName, String permissionName);
+    public abstract void onRevokeRuntimePermission(@NonNull String packageName,
+            @NonNull String permissionName);
 
     @Override
     public final IBinder onBind(Intent intent) {
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 98b69a8..2387657 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -27,6 +27,7 @@
 import android.content.SharedPreferences;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -1167,7 +1168,7 @@
      * @return True if the Preference handled the key. Returns false by default.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public boolean onKey(View v, int keyCode, KeyEvent event) {
         return false;
     }
diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java
index c76c8d3..dfee1af 100644
--- a/core/java/android/preference/PreferenceManager.java
+++ b/core/java/android/preference/PreferenceManager.java
@@ -30,6 +30,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.content.res.XmlResourceParser;
+import android.os.Build;
 import android.os.Bundle;
 import android.util.Log;
 
@@ -68,7 +69,7 @@
      * Fragment that owns this instance.
      */
     @Nullable
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private PreferenceFragment mFragment;
 
     /**
@@ -201,7 +202,7 @@
     /**
      * Sets the owning preference fragment
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     void setFragment(PreferenceFragment fragment) {
         mFragment = fragment;
     }
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 112329e..f126c49 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -2783,7 +2783,48 @@
          * The content:// style URI for this table, which requests a directory of
          * raw contact rows matching the selection criteria.
          */
-        public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "raw_contacts");
+        public static final Uri CONTENT_URI =
+                Uri.withAppendedPath(AUTHORITY_URI, "raw_contacts");
+
+        /**
+         * The URI to register for all raw contacts change notification.
+         *
+         * @hide
+         */
+        @SystemApi
+        @TestApi
+        public static final Uri RAW_CONTACTS_NOTIFICATION_URI =
+                Uri.parse("content://com.android.contacts.raw_contacts");
+
+        /**
+         * The URI to register for raw contacts insert notification.
+         *
+         * @hide
+         */
+        @SystemApi
+        @TestApi
+        public static final Uri RAW_CONTACTS_NOTIFICATION_INSERT_URI =
+                Uri.withAppendedPath(RAW_CONTACTS_NOTIFICATION_URI, "insert");
+
+        /**
+         * The URI to register for raw contacts update notification.
+         *
+         * @hide
+         */
+        @SystemApi
+        @TestApi
+        public static final Uri RAW_CONTACTS_NOTIFICATION_UPDATE_URI =
+                Uri.withAppendedPath(RAW_CONTACTS_NOTIFICATION_URI, "update");
+
+        /**
+         * The URI to register for raw contacts delete notification.
+         *
+         * @hide
+         */
+        @SystemApi
+        @TestApi
+        public static final Uri RAW_CONTACTS_NOTIFICATION_DELETE_URI =
+                Uri.withAppendedPath(RAW_CONTACTS_NOTIFICATION_URI, "delete");
 
         /**
          * The MIME type of the results from {@link #CONTENT_URI} when a specific
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index b12d9cf..ee64ca2 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -1555,7 +1555,7 @@
      *
      * <p>Note, that due to internal limitations, if there is already a web link
      * intent created for the specified document but with different options,
-     * then it may be overriden.
+     * then it may be overridden.
      *
      * <p>Providers are required to show confirmation UI for all new permissions granted
      * for the linked document.
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 81b1921..0e782d7 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -771,7 +771,7 @@
     }
 
     /**
-     * Implementation is provided by the parent class. Cannot be overriden.
+     * Implementation is provided by the parent class. Cannot be overridden.
      *
      * @see #queryRoots(String[])
      * @see #queryRecentDocuments(String, String[])
@@ -828,7 +828,7 @@
     }
 
     /**
-     * Implementation is provided by the parent class. Cannot be overriden.
+     * Implementation is provided by the parent class. Cannot be overridden.
      *
      * @see #getDocumentType(String)
      */
@@ -903,7 +903,7 @@
 
     /**
      * Implementation is provided by the parent class. Throws by default, and
-     * cannot be overriden.
+     * cannot be overridden.
      *
      * @see #createDocument(String, String, String)
      */
@@ -914,7 +914,7 @@
 
     /**
      * Implementation is provided by the parent class. Throws by default, and
-     * cannot be overriden.
+     * cannot be overridden.
      *
      * @see #deleteDocument(String)
      */
@@ -925,7 +925,7 @@
 
     /**
      * Implementation is provided by the parent class. Throws by default, and
-     * cannot be overriden.
+     * cannot be overridden.
      */
     @Override
     public final int update(
@@ -1165,7 +1165,7 @@
     }
 
     /**
-     * Implementation is provided by the parent class. Cannot be overriden.
+     * Implementation is provided by the parent class. Cannot be overridden.
      *
      * @see #openDocument(String, String, CancellationSignal)
      */
@@ -1176,7 +1176,7 @@
     }
 
     /**
-     * Implementation is provided by the parent class. Cannot be overriden.
+     * Implementation is provided by the parent class. Cannot be overridden.
      *
      * @see #openDocument(String, String, CancellationSignal)
      */
@@ -1188,7 +1188,7 @@
     }
 
     /**
-     * Implementation is provided by the parent class. Cannot be overriden.
+     * Implementation is provided by the parent class. Cannot be overridden.
      *
      * @see #openDocument(String, String, CancellationSignal)
      */
@@ -1202,7 +1202,7 @@
     }
 
     /**
-     * Implementation is provided by the parent class. Cannot be overriden.
+     * Implementation is provided by the parent class. Cannot be overridden.
      *
      * @see #openDocument(String, String, CancellationSignal)
      */
@@ -1216,7 +1216,7 @@
     }
 
     /**
-     * Implementation is provided by the parent class. Cannot be overriden.
+     * Implementation is provided by the parent class. Cannot be overridden.
      *
      * @see #openDocumentThumbnail(String, Point, CancellationSignal)
      * @see #openTypedDocument(String, String, Bundle, CancellationSignal)
@@ -1229,7 +1229,7 @@
     }
 
     /**
-     * Implementation is provided by the parent class. Cannot be overriden.
+     * Implementation is provided by the parent class. Cannot be overridden.
      *
      * @see #openDocumentThumbnail(String, Point, CancellationSignal)
      * @see #openTypedDocument(String, String, Bundle, CancellationSignal)
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 189b7b4..82459b1 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -717,7 +717,11 @@
             /**
              * The picasa id of the image
              * <P>Type: TEXT</P>
+             *
+             * @deprecated this value was only relevant for images hosted on
+             *             Picasa, which are no longer supported.
              */
+            @Deprecated
             public static final String PICASA_ID = "picasa_id";
 
             /**
@@ -755,7 +759,12 @@
             /**
              * The mini thumb id.
              * <P>Type: INTEGER</P>
+             *
+             * @deprecated all thumbnails should be obtained via
+             *             {@link Images.Thumbnails#getThumbnail}, as this
+             *             value is no longer supported.
              */
+            @Deprecated
             public static final String MINI_THUMB_MAGIC = "mini_thumb_magic";
 
             /**
@@ -1947,7 +1956,12 @@
             /**
              * The mini thumb id.
              * <P>Type: INTEGER</P>
+             *
+             * @deprecated all thumbnails should be obtained via
+             *             {@link Images.Thumbnails#getThumbnail}, as this
+             *             value is no longer supported.
              */
+            @Deprecated
             public static final String MINI_THUMB_MAGIC = "mini_thumb_magic";
 
             /**
diff --git a/core/java/android/provider/SearchIndexablesProvider.java b/core/java/android/provider/SearchIndexablesProvider.java
index 138e77b..02a5e6f 100644
--- a/core/java/android/provider/SearchIndexablesProvider.java
+++ b/core/java/android/provider/SearchIndexablesProvider.java
@@ -181,7 +181,7 @@
     }
 
     /**
-     * Implementation is provided by the parent class. Throws by default, and cannot be overriden.
+     * Implementation is provided by the parent class. Throws by default, and cannot be overridden.
      */
     @Override
     public final Uri insert(Uri uri, ContentValues values) {
@@ -189,7 +189,7 @@
     }
 
     /**
-     * Implementation is provided by the parent class. Throws by default, and cannot be overriden.
+     * Implementation is provided by the parent class. Throws by default, and cannot be overridden.
      */
     @Override
     public final int delete(Uri uri, String selection, String[] selectionArgs) {
@@ -197,7 +197,7 @@
     }
 
     /**
-     * Implementation is provided by the parent class. Throws by default, and cannot be overriden.
+     * Implementation is provided by the parent class. Throws by default, and cannot be overridden.
      */
     @Override
     public final int update(
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 026195e..8fd9d4f 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -363,6 +363,21 @@
             "android.settings.MANAGE_UNKNOWN_APP_SOURCES";
 
     /**
+     * Activity Action: Show the "Open by Default" page in a particular application's details page.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you safeguard against this.
+     * <p>
+     * Input: The Intent's data URI specifies the application package name
+     * to be shown, with the "package" scheme. That is "package:com.my.app".
+     * <p>
+     * Output: Nothing.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_APP_OPEN_BY_DEFAULT_SETTINGS =
+            "com.android.settings.APP_OPEN_BY_DEFAULT_SETTINGS";
+
+    /**
      * Activity Action: Show trusted credentials settings, opening to the user tab,
      * to allow management of installed credentials.
      * <p>
@@ -809,21 +824,6 @@
             "android.settings.APPLICATION_DETAILS_SETTINGS";
 
     /**
-     * Activity Action: Show the "Open by Default" page in a particular application's details page.
-     * <p>
-     * In some cases, a matching Activity may not exist, so ensure you safeguard against this.
-     * <p>
-     * Input: The Intent's data URI specifies the application package name
-     * to be shown, with the "package" scheme. That is "package:com.my.app".
-     * <p>
-     * Output: Nothing.
-     * @hide
-     */
-    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-    public static final String ACTION_APPLICATION_DETAILS_SETTINGS_OPEN_BY_DEFAULT_PAGE =
-            "android.settings.APPLICATION_DETAILS_SETTINGS_OPEN_BY_DEFAULT_PAGE";
-
-    /**
      * Activity Action: Show list of applications that have been running
      * foreground services (to the user "running in the background").
      * <p>
@@ -7689,6 +7689,15 @@
                 BOOLEAN_VALIDATOR;
 
         /**
+         * Whether or not face unlock is allowed for apps (through BiometricPrompt).
+         * @hide
+         */
+        public static final String FACE_UNLOCK_APP_ENABLED = "face_unlock_app_enabled";
+
+        private static final Validator FACE_UNLOCK_APP_ENABLED_VALIDATOR =
+                BOOLEAN_VALIDATOR;
+
+        /**
          * Whether the assist gesture should be enabled.
          *
          * @hide
@@ -8189,6 +8198,7 @@
             NFC_PAYMENT_DEFAULT_COMPONENT,
             AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN,
             FACE_UNLOCK_KEYGUARD_ENABLED,
+            FACE_UNLOCK_APP_ENABLED,
             ASSIST_GESTURE_ENABLED,
             ASSIST_GESTURE_SILENCE_ALERTS_ENABLED,
             ASSIST_GESTURE_WAKE_ENABLED,
@@ -8337,6 +8347,7 @@
             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_APP_ENABLED, FACE_UNLOCK_APP_ENABLED_VALIDATOR);
             VALIDATORS.put(ASSIST_GESTURE_ENABLED, ASSIST_GESTURE_ENABLED_VALIDATOR);
             VALIDATORS.put(ASSIST_GESTURE_SILENCE_ALERTS_ENABLED,
                     ASSIST_GESTURE_SILENCE_ALERTS_ENABLED_VALIDATOR);
@@ -11537,14 +11548,6 @@
         public static final String EMERGENCY_AFFORDANCE_NEEDED = "emergency_affordance_needed";
 
         /**
-         * Enable faster emergency phone call feature.
-         * The value is a boolean (1 or 0).
-         * @hide
-         */
-        public static final String FASTER_EMERGENCY_PHONE_CALL_ENABLED =
-                "faster_emergency_phone_call_enabled";
-
-        /**
          * See RIL_PreferredNetworkType in ril.h
          * @hide
          */
diff --git a/core/java/android/security/net/config/DirectoryCertificateSource.java b/core/java/android/security/net/config/DirectoryCertificateSource.java
index 119f5d0..4f4d62a 100644
--- a/core/java/android/security/net/config/DirectoryCertificateSource.java
+++ b/core/java/android/security/net/config/DirectoryCertificateSource.java
@@ -16,26 +16,23 @@
 
 package android.security.net.config;
 
-import android.os.Environment;
-import android.os.UserHandle;
 import android.util.ArraySet;
 import android.util.Log;
-import android.util.Pair;
+
+import libcore.io.IoUtils;
+
 import java.io.BufferedInputStream;
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.InputStream;
 import java.io.IOException;
-import java.security.cert.Certificate;
+import java.io.InputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
 import java.util.Collections;
 import java.util.Set;
-import libcore.io.IoUtils;
-
-import com.android.org.conscrypt.Hex;
-import com.android.org.conscrypt.NativeCrypto;
 
 import javax.security.auth.x500.X500Principal;
 
@@ -192,8 +189,36 @@
     }
 
     private String getHash(X500Principal name) {
-        int hash = NativeCrypto.X509_NAME_hash_old(name);
-        return Hex.intToHexString(hash, 8);
+        int hash = hashName(name);
+        return intToHexString(hash, 8);
+    }
+
+    private static final char[] DIGITS = {
+            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+    private static String intToHexString(int i, int minWidth) {
+        int bufLen = 8;  // Max number of hex digits in an int
+        char[] buf = new char[bufLen];
+        int cursor = bufLen;
+
+        do {
+            buf[--cursor] = DIGITS[i & 0xf];
+        } while ((i >>>= 4) != 0 || (bufLen - cursor < minWidth));
+
+        return new String(buf, cursor, bufLen - cursor);
+    }
+
+    // This code matches the code in X509_NAME_hash_old() in Conscrypt, which in turn matches
+    // the names of certificate files.  It must be kept in sync.
+    private static int hashName(X500Principal principal) {
+        try {
+            byte[] digest = MessageDigest.getInstance("MD5").digest(principal.getEncoded());
+            int offset = 0;
+            return (((digest[offset++] & 0xff) << 0) | ((digest[offset++] & 0xff) << 8)
+                    | ((digest[offset++] & 0xff) << 16) | ((digest[offset] & 0xff) << 24));
+        } catch (NoSuchAlgorithmException e) {
+            throw new AssertionError(e);
+        }
     }
 
     private X509Certificate readCertificate(String file) {
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 6c18b45..573d577 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -651,14 +651,11 @@
     /**
      * Called when the user requests the service to save the contents of a screen.
      *
-     * <p>Service must call one of the {@link SaveCallback} methods (like
-     * {@link SaveCallback#onSuccess()} or {@link SaveCallback#onFailure(CharSequence)})
-     * to notify the Android System of the result of the request.
-     *
      * <p>If the service could not handle the request right away&mdash;for example, because it must
      * launch an activity asking the user to authenticate first or because the network is
      * down&mdash;the service could keep the {@link SaveRequest request} and reuse it later,
-     * but the service must call {@link SaveCallback#onSuccess()} right away.
+     * but the service <b>must always</b> call {@link SaveCallback#onSuccess()} or
+     * {@link SaveCallback#onSuccess(android.content.IntentSender)} right away.
      *
      * <p><b>Note:</b> To retrieve the actual value of fields input by the user, the service
      * should call
diff --git a/core/java/android/service/autofill/CustomDescription.java b/core/java/android/service/autofill/CustomDescription.java
index b1ae7a5..fdbb1c2 100644
--- a/core/java/android/service/autofill/CustomDescription.java
+++ b/core/java/android/service/autofill/CustomDescription.java
@@ -314,7 +314,8 @@
          * is called multiple times passing the same {@code id}, only the last call will be used.
          *
          * @param id resource id of the child view.
-         * @param action action to be performed.
+         * @param action action to be performed. Must be an an implementation provided by the
+         * Android System.
          *
          * @return this builder
          *
diff --git a/core/java/android/service/autofill/FillCallback.java b/core/java/android/service/autofill/FillCallback.java
index 1695c13..06e2896 100644
--- a/core/java/android/service/autofill/FillCallback.java
+++ b/core/java/android/service/autofill/FillCallback.java
@@ -19,6 +19,7 @@
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.os.RemoteException;
+import android.util.Log;
 
 /**
  * <p><code>FillCallback</code> handles autofill requests from the {@link AutofillService} into
@@ -28,6 +29,9 @@
  * <a href="/guide/topics/text/autofill-services">Build autofill services</a>.
  */
 public final class FillCallback {
+
+    private static final String TAG = "FillCallback";
+
     private final IFillCallback mCallback;
     private final int mRequestId;
     private boolean mCalled;
@@ -39,13 +43,20 @@
     }
 
     /**
-     * Notifies the Android System that an
-     * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal,
-     * FillCallback)} was successfully fulfilled by the service.
+     * Notifies the Android System that a fill request
+     * ({@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal,
+     * FillCallback)}) was successfully fulfilled by the service.
      *
-     * @param response autofill information for that activity, or {@code null} when the activity
-     * cannot be autofilled (for example, if it only contains read-only fields). See
-     * {@link FillResponse} for examples.
+     * <p>This method should always be called, even if the service doesn't have the heuristics to
+     * fulfill the request (in which case it should be called with {@code null}).
+     *
+     * <p>See the main {@link AutofillService} documentation for more details and examples.
+     *
+     * @param response autofill information for that activity, or {@code null} when the service
+     * cannot autofill the activity.
+     *
+     * @throws IllegalStateException if this method or {@link #onFailure(CharSequence)} was already
+     * called.
      */
     public void onSuccess(@Nullable FillResponse response) {
         assertNotCalled();
@@ -63,13 +74,33 @@
     }
 
     /**
-     * Notifies the Android System that an
+     * Notifies the Android System that a fill request (
      * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal,
-     * FillCallback)} could not be fulfilled by the service.
+     * FillCallback)}) could not be fulfilled by the service (for example, because the user data was
+     * not available yet), so the request could be retried later.
      *
-     * @param message error message to be displayed to the user.
+     * <p><b>Note: </b>this method should not be used when the service didn't have the heursitics to
+     * fulfill the request; in this case, the service should call {@link #onSuccess(FillResponse)
+     * onSuccess(null)} instead.
+     *
+     * <p><b>Note: </b>prior to {@link android.os.Build.VERSION_CODES#Q}, this
+     * method was not working as intended and the service should always call
+     * {@link #onSuccess(FillResponse) onSuccess(null)} instead.
+     *
+     * <p><b>Note: </b>for apps targeting {@link android.os.Build.VERSION_CODES#Q} or higher, this
+     * method just logs the message on {@code logcat}; for apps targetting older SDKs, it also
+     * displays the message to user using a {@link android.widget.Toast}. Generally speaking, you
+     * should not display an error to the user if the request failed, unless the request had the
+     * {@link FillRequest#FLAG_MANUAL_REQUEST} flag.
+     *
+     * @param message error message. <b>Note: </b> this message should <b>not</b> contain PII
+     * (Personally Identifiable Information, such as username or email address).
+     *
+     * @throws IllegalStateException if this method or {@link #onSuccess(FillResponse)} was already
+     * called.
      */
     public void onFailure(@Nullable CharSequence message) {
+        Log.w(TAG, "onFailure(): " + message);
         assertNotCalled();
         mCalled = true;
         try {
diff --git a/core/java/android/service/autofill/OnClickAction.java b/core/java/android/service/autofill/OnClickAction.java
index 7439b00..8597a88 100644
--- a/core/java/android/service/autofill/OnClickAction.java
+++ b/core/java/android/service/autofill/OnClickAction.java
@@ -21,6 +21,9 @@
  *
  * <p>Typically used to switch the visibility of other views in a
  * {@link CustomDescription custom save UI}.
+ *
+ * <p><b>Note:</b> This interface is not meant to be implemented by app developers; only
+ * implementations provided by the Android System can be used in other Autofill APIs.
  */
 public interface OnClickAction {
 }
diff --git a/core/java/android/service/autofill/Sanitizer.java b/core/java/android/service/autofill/Sanitizer.java
index 38757ac..8a1310d 100644
--- a/core/java/android/service/autofill/Sanitizer.java
+++ b/core/java/android/service/autofill/Sanitizer.java
@@ -21,6 +21,9 @@
  * <p>Typically used to avoid displaying the save UI for values that are autofilled but reformatted
  * by the app&mdash;for example, if the autofill service sends a credit card number
  * value as "004815162342108" and the app automatically changes it to "0048 1516 2342 108".
+ *
+ * <p><b>Note:</b> This interface is not meant to be implemented by app developers; only
+ * implementations provided by the Android System can be used in other Autofill APIs.
  */
 public interface Sanitizer {
 }
diff --git a/core/java/android/service/autofill/SaveCallback.java b/core/java/android/service/autofill/SaveCallback.java
index 855981a..1753ecf 100644
--- a/core/java/android/service/autofill/SaveCallback.java
+++ b/core/java/android/service/autofill/SaveCallback.java
@@ -21,6 +21,7 @@
 import android.app.Activity;
 import android.content.IntentSender;
 import android.os.RemoteException;
+import android.util.Log;
 
 import com.android.internal.util.Preconditions;
 
@@ -29,6 +30,9 @@
  * autofilled.
  */
 public final class SaveCallback {
+
+    private static final String TAG = "SaveCallback";
+
     private final ISaveCallback mCallback;
     private boolean mCalled;
 
@@ -41,6 +45,9 @@
      * Notifies the Android System that an
      * {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)} was successfully handled
      * by the service.
+     *
+     * @throws IllegalStateException if this method, {@link #onSuccess(IntentSender)}, or
+     * {@link #onFailure(CharSequence)} was already called.
      */
     public void onSuccess() {
         onSuccessInternal(null);
@@ -58,6 +65,9 @@
      *
      * @param intentSender intent that will be launched from the context of activity being
      * autofilled.
+     *
+     * @throws IllegalStateException if this method, {@link #onSuccess()},
+     * or {@link #onFailure(CharSequence)} was already called.
      */
     public void onSuccess(@NonNull IntentSender intentSender) {
         onSuccessInternal(Preconditions.checkNotNull(intentSender));
@@ -73,22 +83,30 @@
         }
     }
 
+
+
+
     /**
      * Notifies the Android System that an
      * {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)} could not be handled
      * by the service.
      *
-     * <p>This method should only be called when the service could not handle the request right away
-     * and could not recover or retry it. If the service could retry or recover, it could keep
-     * the {@link SaveRequest} and call {@link #onSuccess()} instead.
+     * <p>This method is just used for logging purposes, the Android System won't call the service
+     * again in case of failures&mdash;if you need to recover from the failure, just save the
+     * {@link SaveRequest} and try again later.
      *
-     * <p><b>Note:</b> The Android System displays an UI with the supplied error message; if
-     * you prefer to show your own message, call {@link #onSuccess()} or
-     * {@link #onSuccess(IntentSender)} instead.
+     * <p><b>Note: </b>for apps targeting {@link android.os.Build.VERSION_CODES#Q} or higher, this
+     * method just logs the message on {@code logcat}; for apps targetting older SDKs, it also
+     * displays the message to user using a {@link android.widget.Toast}.
      *
-     * @param message error message to be displayed to the user.
+     * @param message error message. <b>Note: </b> this message should <b>not</b> contain PII
+     * (Personally Identifiable Information, such as username or email address).
+     *
+     * @throws IllegalStateException if this method, {@link #onSuccess()},
+     * or {@link #onSuccess(IntentSender)} was already called.
      */
     public void onFailure(CharSequence message) {
+        Log.w(TAG, "onFailure(): " + message);
         assertNotCalled();
         mCalled = true;
         try {
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index f571956..dfaf49a 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -235,12 +235,17 @@
      */
     public static final int FLAG_DONT_SAVE_ON_FINISH = 0x2;
 
+
     /**
-     * Don't trigger the autofill save UI when the autofill context associated with the response
-     * associated with this {@link SaveInfo} is {@link AutofillManager#commit() committed},
-     * but keep its {@link FillContext} so it's delivered in a future
-     * {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback) save request} of an
-     * activity belonging to the same task.
+     * Postpone the autofill save UI.
+     *
+     * <p>If flag is set, the autofill save UI is not triggered when the
+     * autofill context associated with the response associated with this {@link SaveInfo} is
+     * committed (with {@link AutofillManager#commit()}). Instead, the {@link FillContext}
+     * is delivered in future fill requests (with {@link
+     * AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)})
+     * and save request (with {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)})
+     * of an activity belonging to the same task.
      *
      * <p>This flag should be used when the service detects that the application uses
      * multiple screens to implement an autofillable workflow (for example, one screen for the
diff --git a/core/java/android/service/autofill/Transformation.java b/core/java/android/service/autofill/Transformation.java
index aa8bc9b..de43955 100644
--- a/core/java/android/service/autofill/Transformation.java
+++ b/core/java/android/service/autofill/Transformation.java
@@ -20,6 +20,9 @@
  * template} at runtime, using the values of fields contained in the screen.
  *
  * <p>Typically used by {@link CustomDescription} to provide a customized autofill save UI.
+ *
+ * <p><b>Note:</b> This interface is not meant to be implemented by app developers; only
+ * implementations provided by the Android System can be used in other Autofill APIs.
  */
 public interface Transformation {
 }
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 15b2aae..38de794 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -27,6 +27,7 @@
 import android.content.Intent;
 import android.graphics.PixelFormat;
 import android.graphics.drawable.ColorDrawable;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.IRemoteCallback;
@@ -626,7 +627,7 @@
      * @see #startDozing
      * @hide For use by system UI components only.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public boolean canDoze() {
         return mCanDoze;
     }
@@ -694,7 +695,7 @@
      * @see #startDozing
      * @hide For use by system UI components only.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public void stopDozing() {
         if (mDozing) {
             mDozing = false;
@@ -716,7 +717,7 @@
      * @see #setDozing(boolean)
      * @hide For use by system UI components only.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public boolean isDozing() {
         return mDozing;
     }
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index 26240c5..c1a3c2b 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -283,6 +283,9 @@
                         } catch (android.os.RemoteException ex) {
                             Log.v(TAG, "Unable to contact notification manager", ex);
                             throw ex.rethrowFromSystemServer();
+                        } catch (SecurityException e) {
+                            // app cannot catch and recover from this, so do on their behalf
+                            Log.w(TAG, "Enqueue adjustment failed; no longer connected", e);
                         }
                     }
                     break;
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index d9ed2aa..d7fe15d 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -280,7 +280,7 @@
 
     private final Object mLock = new Object();
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private Handler mHandler;
 
     /** @hide */
@@ -989,6 +989,21 @@
     }
 
     /**
+     * Clears listener hints set via {@link #getCurrentListenerHints()}.
+     *
+     * <p>The service should wait for the {@link #onListenerConnected()} event
+     * before performing this operation.
+     */
+    public final void clearRequestedListenerHints() {
+        if (!isBound()) return;
+        try {
+            getNotificationInterface().clearRequestedListenerHints(mWrapper);
+        } catch (android.os.RemoteException ex) {
+            Log.v(TAG, "Unable to contact notification manager", ex);
+        }
+    }
+
+    /**
      * Sets the desired {@link #getCurrentListenerHints() listener hints}.
      *
      * <p>
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index f90eb14..5012d77 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -16,6 +16,7 @@
 
 package android.service.notification;
 
+import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_REMINDERS;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
@@ -145,6 +146,7 @@
     private static final String RULE_ATT_CONDITION_ID = "conditionId";
     private static final String RULE_ATT_CREATION_TIME = "creationTime";
     private static final String RULE_ATT_ENABLER = "enabler";
+    private static final String RULE_ATT_MODIFIED = "modified";
 
     @UnsupportedAppUsage
     public boolean allowAlarms = DEFAULT_ALLOW_ALARMS;
@@ -632,6 +634,7 @@
             Slog.i(TAG, "Updating zenMode of automatic rule " + rt.name);
             rt.zenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         }
+        rt.modified = safeBoolean(parser, RULE_ATT_MODIFIED, false);
         return rt;
     }
 
@@ -655,6 +658,7 @@
         if (rule.condition != null) {
             writeConditionXml(rule.condition, out);
         }
+        out.attribute(null, RULE_ATT_MODIFIED, Boolean.toString(rule.modified));
     }
 
     public static Condition readConditionXml(XmlPullParser parser) {
@@ -763,6 +767,145 @@
         }
     };
 
+    /**
+     * @return notification policy based on manual and automatic rules
+     */
+    public Policy getConsolidatedNotificationPolicy() {
+        ZenPolicy policy = new ZenPolicy();
+
+        // assumption: manual rule always uses the default policy
+        for (ZenRule rule : automaticRules.values()) {
+            if (rule.isAutomaticActive()) {
+                if (rule.zenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {
+                    policy.apply(rule.zenPolicy);
+                }
+            }
+        }
+
+        return toNotificationPolicy(policy);
+    }
+
+    /**
+     * Converts a zenPolicy to a notificationPolicy using this ZenModeConfig's values as its
+     * defaults for all unset values in zenPolicy
+     */
+    public Policy toNotificationPolicy(ZenPolicy zenPolicy) {
+        NotificationManager.Policy defaultPolicy = toNotificationPolicy();
+        int priorityCategories = 0;
+        int suppressedVisualEffects = 0;
+        int callSenders = defaultPolicy.priorityCallSenders;
+        int messageSenders = defaultPolicy.priorityMessageSenders;
+
+        if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_REMINDERS,
+                isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_REMINDERS, defaultPolicy))) {
+            priorityCategories |= PRIORITY_CATEGORY_REMINDERS;
+        }
+
+        if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_EVENTS,
+                isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_EVENTS, defaultPolicy))) {
+            priorityCategories |= Policy.PRIORITY_CATEGORY_EVENTS;
+        }
+
+        if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_MESSAGES,
+                isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_MESSAGES, defaultPolicy))) {
+            priorityCategories |= Policy.PRIORITY_CATEGORY_MESSAGES;
+            messageSenders = getNotificationPolicySenders(zenPolicy.getPriorityMessageSenders());
+        }
+
+        if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_CALLS,
+                isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_CALLS, defaultPolicy))) {
+            priorityCategories |= Policy.PRIORITY_CATEGORY_CALLS;
+            messageSenders = getNotificationPolicySenders(zenPolicy.getPriorityCallSenders());
+        }
+
+        if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_REPEAT_CALLERS,
+                isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_REPEAT_CALLERS,
+                        defaultPolicy))) {
+            priorityCategories |= Policy.PRIORITY_CATEGORY_REPEAT_CALLERS;
+        }
+
+        if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_ALARMS,
+                isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_ALARMS, defaultPolicy))) {
+            priorityCategories |= Policy.PRIORITY_CATEGORY_ALARMS;
+        }
+
+        if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_MEDIA,
+                isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_MEDIA, defaultPolicy))) {
+            priorityCategories |= Policy.PRIORITY_CATEGORY_MEDIA;
+        }
+
+        if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_SYSTEM,
+                isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_SYSTEM, defaultPolicy))) {
+            priorityCategories |= Policy.PRIORITY_CATEGORY_SYSTEM;
+        }
+
+        if (!zenPolicy.isVisualEffectAllowed(ZenPolicy.VISUAL_EFFECT_FULL_SCREEN_INTENT,
+                isVisualEffectAllowed(Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT,
+                        defaultPolicy))) {
+            suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+        }
+
+        if (!zenPolicy.isVisualEffectAllowed(ZenPolicy.VISUAL_EFFECT_LIGHTS,
+                isVisualEffectAllowed(Policy.SUPPRESSED_EFFECT_LIGHTS,
+                        defaultPolicy))) {
+            suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_LIGHTS;
+        }
+
+        if (!zenPolicy.isVisualEffectAllowed(ZenPolicy.VISUAL_EFFECT_PEEK,
+                isVisualEffectAllowed(Policy.SUPPRESSED_EFFECT_PEEK,
+                        defaultPolicy))) {
+            suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_PEEK;
+        }
+
+        if (!zenPolicy.isVisualEffectAllowed(ZenPolicy.VISUAL_EFFECT_STATUS_BAR,
+                isVisualEffectAllowed(Policy.SUPPRESSED_EFFECT_STATUS_BAR,
+                        defaultPolicy))) {
+            suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_STATUS_BAR;
+        }
+
+        if (!zenPolicy.isVisualEffectAllowed(ZenPolicy.VISUAL_EFFECT_BADGE,
+                isVisualEffectAllowed(Policy.SUPPRESSED_EFFECT_BADGE,
+                        defaultPolicy))) {
+            suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_BADGE;
+        }
+
+        if (!zenPolicy.isVisualEffectAllowed(ZenPolicy.VISUAL_EFFECT_AMBIENT,
+                isVisualEffectAllowed(Policy.SUPPRESSED_EFFECT_AMBIENT,
+                        defaultPolicy))) {
+            suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_AMBIENT;
+        }
+
+        if (!zenPolicy.isVisualEffectAllowed(ZenPolicy.VISUAL_EFFECT_NOTIFICATION_LIST,
+                isVisualEffectAllowed(Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST,
+                        defaultPolicy))) {
+            suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
+        }
+
+        return new NotificationManager.Policy(priorityCategories, callSenders,
+                messageSenders, suppressedVisualEffects);
+    }
+
+    private boolean isPriorityCategoryEnabled(int categoryType, Policy policy) {
+        return (policy.priorityCategories & categoryType) != 0;
+    }
+
+    private boolean isVisualEffectAllowed(int visualEffect, Policy policy) {
+        return (policy.suppressedVisualEffects & visualEffect) == 0;
+    }
+
+    private int getNotificationPolicySenders(@ZenPolicy.PeopleType int senders) {
+        switch (senders) {
+            case ZenPolicy.PEOPLE_TYPE_ANYONE:
+                return Policy.PRIORITY_SENDERS_ANY;
+            case ZenPolicy.PEOPLE_TYPE_CONTACTS:
+                return Policy.PRIORITY_SENDERS_CONTACTS;
+            case ZenPolicy.PEOPLE_TYPE_STARRED:
+            default:
+                return Policy.PRIORITY_SENDERS_STARRED;
+        }
+
+    }
+
     public Policy toNotificationPolicy() {
         int priorityCategories = 0;
         int priorityCallSenders = Policy.PRIORITY_SENDERS_CONTACTS;
@@ -1315,6 +1458,8 @@
         @UnsupportedAppUsage
         public long creationTime;        // required for automatic
         public String enabler;          // package name, only used for manual rules.
+        public ZenPolicy zenPolicy;
+        public boolean modified;    // rule has been modified from initial creation
 
         public ZenRule() { }
 
@@ -1335,6 +1480,8 @@
             if (source.readInt() == 1) {
                 enabler = source.readString();
             }
+            zenPolicy = source.readParcelable(null);
+            modified = source.readInt() == 1;
         }
 
         @Override
@@ -1369,6 +1516,8 @@
             } else {
                 dest.writeInt(0);
             }
+            dest.writeParcelable(zenPolicy, 0);
+            dest.writeInt(modified ? 1 : 0);
         }
 
         @Override
@@ -1384,6 +1533,8 @@
                     .append(",component=").append(component)
                     .append(",creationTime=").append(creationTime)
                     .append(",enabler=").append(enabler)
+                    .append(",zenPolicy=").append(zenPolicy)
+                    .append(",modified=").append(modified)
                     .append(']').toString();
         }
 
@@ -1407,7 +1558,10 @@
             if (component != null) {
                 component.writeToProto(proto, ZenRuleProto.COMPONENT);
             }
-
+            if (zenPolicy != null) {
+                zenPolicy.writeToProto(proto, ZenRuleProto.ZEN_POLICY);
+            }
+            proto.write(ZenRuleProto.MODIFIED, modified);
             proto.end(token);
         }
 
@@ -1454,9 +1608,15 @@
             if (creationTime != to.creationTime) {
                 d.addLine(item, "creationTime", creationTime, to.creationTime);
             }
-            if (enabler != to.enabler) {
+            if (!Objects.equals(enabler, to.enabler)) {
                 d.addLine(item, "enabler", enabler, to.enabler);
             }
+            if (!Objects.equals(zenPolicy, to.zenPolicy)) {
+                d.addLine(item, "zenPolicy", zenPolicy, to.zenPolicy);
+            }
+            if (modified != to.modified) {
+                d.addLine(item, "modified", modified, to.modified);
+            }
         }
 
         @Override
@@ -1472,13 +1632,15 @@
                     && Objects.equals(other.condition, condition)
                     && Objects.equals(other.component, component)
                     && Objects.equals(other.id, id)
-                    && Objects.equals(other.enabler, enabler);
+                    && Objects.equals(other.enabler, enabler)
+                    && Objects.equals(other.zenPolicy, zenPolicy)
+                    && other.modified == modified;
         }
 
         @Override
         public int hashCode() {
             return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition,
-                    component, id, enabler);
+                    component, id, enabler, zenPolicy, modified);
         }
 
         public boolean isAutomaticActive() {
diff --git a/core/java/android/service/notification/ZenPolicy.java b/core/java/android/service/notification/ZenPolicy.java
new file mode 100644
index 0000000..1ccf529
--- /dev/null
+++ b/core/java/android/service/notification/ZenPolicy.java
@@ -0,0 +1,897 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.notification;
+
+import android.annotation.IntDef;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.proto.ProtoOutputStream;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Objects;
+
+/**
+ * ZenPolicy determines whether to allow certain notifications and their corresponding sounds to
+ * play when a device is in Do Not Disturb mode.
+ * ZenPolicy also dictates the visual effects of notifications that are intercepted when
+ * a device is in Do Not Disturb mode.
+ */
+public final class ZenPolicy implements Parcelable {
+    private ArrayList<Integer> mPriorityCategories;
+    private ArrayList<Integer> mVisualEffects;
+    private @PeopleType int mPriorityMessages = PEOPLE_TYPE_UNSET;
+    private @PeopleType int mPriorityCalls = PEOPLE_TYPE_UNSET;
+
+    /** @hide */
+    @IntDef(prefix = { "PRIORITY_CATEGORY_" }, value = {
+            PRIORITY_CATEGORY_REMINDERS,
+            PRIORITY_CATEGORY_EVENTS,
+            PRIORITY_CATEGORY_MESSAGES,
+            PRIORITY_CATEGORY_CALLS,
+            PRIORITY_CATEGORY_REPEAT_CALLERS,
+            PRIORITY_CATEGORY_ALARMS,
+            PRIORITY_CATEGORY_MEDIA,
+            PRIORITY_CATEGORY_SYSTEM,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PriorityCategory {}
+
+    /** @hide */
+    public static final int PRIORITY_CATEGORY_REMINDERS = 0;
+    /** @hide */
+    public static final int PRIORITY_CATEGORY_EVENTS = 1;
+    /** @hide */
+    public static final int PRIORITY_CATEGORY_MESSAGES = 2;
+    /** @hide */
+    public static final int PRIORITY_CATEGORY_CALLS = 3;
+    /** @hide */
+    public static final int PRIORITY_CATEGORY_REPEAT_CALLERS = 4;
+    /** @hide */
+    public static final int PRIORITY_CATEGORY_ALARMS = 5;
+    /** @hide */
+    public static final int PRIORITY_CATEGORY_MEDIA = 6;
+    /** @hide */
+    public static final int PRIORITY_CATEGORY_SYSTEM = 7;
+
+    /** @hide */
+    @IntDef(prefix = { "VISUAL_EFFECT_" }, value = {
+            VISUAL_EFFECT_FULL_SCREEN_INTENT,
+            VISUAL_EFFECT_LIGHTS,
+            VISUAL_EFFECT_PEEK,
+            VISUAL_EFFECT_STATUS_BAR,
+            VISUAL_EFFECT_BADGE,
+            VISUAL_EFFECT_AMBIENT,
+            VISUAL_EFFECT_NOTIFICATION_LIST,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface VisualEffect {}
+
+    /** @hide */
+    public static final int VISUAL_EFFECT_FULL_SCREEN_INTENT = 0;
+    /** @hide */
+    public static final int VISUAL_EFFECT_LIGHTS = 1;
+    /** @hide */
+    public static final int VISUAL_EFFECT_PEEK = 2;
+    /** @hide */
+    public static final int VISUAL_EFFECT_STATUS_BAR = 3;
+    /** @hide */
+    public static final int VISUAL_EFFECT_BADGE = 4;
+    /** @hide */
+    public static final int VISUAL_EFFECT_AMBIENT = 5;
+    /** @hide */
+    public static final int VISUAL_EFFECT_NOTIFICATION_LIST = 6;
+
+    /** @hide */
+    @IntDef(prefix = { "PEOPLE_TYPE_" }, value = {
+            PEOPLE_TYPE_UNSET,
+            PEOPLE_TYPE_ANYONE,
+            PEOPLE_TYPE_CONTACTS,
+            PEOPLE_TYPE_STARRED,
+            PEOPLE_TYPE_NONE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PeopleType {}
+
+    /**
+     * Used to indicate no preference for the type of people that can bypass dnd for either
+     * calls or messages.
+     */
+    public static final int PEOPLE_TYPE_UNSET = 0;
+
+    /**
+     * Used to indicate all calls or messages can bypass dnd.
+     */
+    public static final int PEOPLE_TYPE_ANYONE = 1;
+
+    /**
+     * Used to indicate calls or messages from contacts can bypass dnd.
+     */
+    public static final int PEOPLE_TYPE_CONTACTS = 2;
+
+    /**
+     * Used to indicate calls or messages from starred contacts can bypass dnd.
+     */
+    public static final int PEOPLE_TYPE_STARRED = 3;
+
+    /**
+     * Used to indicate no calls or messages can bypass dnd.
+     */
+    public static final int PEOPLE_TYPE_NONE = 4;
+
+    /** @hide */
+    @IntDef(prefix = { "STATE_" }, value = {
+            STATE_UNSET,
+            STATE_ALLOW,
+            STATE_DISALLOW,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface State {}
+
+    /**
+     * Indicates no preference for whether a type of sound or visual effect is or isn't allowed
+     * to play/show when DND is active.  Will default to the current set policy.
+     */
+    public static final int STATE_UNSET = 0;
+
+    /**
+     * Indicates a type of sound or visual effect is allowed to play/show when DND is active.
+     */
+    public static final int STATE_ALLOW = 1;
+
+    /**
+     * Indicates a type of sound or visual effect is not allowed to play/show when DND is active.
+     */
+    public static final int STATE_DISALLOW = 2;
+
+    /** @hide */
+    public ZenPolicy() {
+        mPriorityCategories = new ArrayList<>(Collections.nCopies(8, 0));
+        mVisualEffects = new ArrayList<>(Collections.nCopies(7, 0));
+    }
+
+    /**
+     * Message senders that can bypass DND.
+     * @return {@link #PEOPLE_TYPE_UNSET}, {@link #PEOPLE_TYPE_ANYONE},
+     * {@link #PEOPLE_TYPE_CONTACTS}, {@link #PEOPLE_TYPE_STARRED} or {@link #PEOPLE_TYPE_NONE}
+     */
+    public @PeopleType int getPriorityMessageSenders() {
+        return mPriorityMessages;
+    }
+
+    /**
+     * Callers that can bypass DND.
+     * @return {@link #PEOPLE_TYPE_UNSET}, {@link #PEOPLE_TYPE_ANYONE},
+     * {@link #PEOPLE_TYPE_CONTACTS}, {@link #PEOPLE_TYPE_STARRED} or {@link #PEOPLE_TYPE_NONE}
+     */
+    public @PeopleType int getPriorityCallSenders() {
+        return mPriorityCalls;
+    }
+
+    /**
+     * Whether this policy wants to allow notifications with category
+     * {@link Notification#CATEGORY_REMINDER} to play sounds and visually appear
+     * or to intercept them when DND is active.
+     * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
+     */
+    public @State int getPriorityCategoryReminders() {
+        return mPriorityCategories.get(PRIORITY_CATEGORY_REMINDERS);
+    }
+
+    /**
+     * Whether this policy wants to allow notifications with category
+     * {@link Notification#CATEGORY_EVENT} to play sounds and visually appear
+     * or to intercept them when DND is active.
+     * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
+     */
+    public @State int getPriorityCategoryEvents() {
+        return mPriorityCategories.get(PRIORITY_CATEGORY_EVENTS);
+    }
+
+    /**
+     * Whether this policy wants to allow notifications with category
+     * {@link Notification#CATEGORY_MESSAGE} to play sounds and visually appear
+     * or to intercept them when DND is active.  Types of message senders that are allowed
+     * are specified by {@link #getPriorityMessageSenders}.
+     * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
+     */
+    public @State int getPriorityCategoryMessages() {
+        return mPriorityCategories.get(PRIORITY_CATEGORY_MESSAGES);
+    }
+
+    /**
+     * Whether this policy wants to allow notifications with category
+     * {@link Notification#CATEGORY_CALL} to play sounds and visually appear
+     * or to intercept them when DND is active.  Types of callers that are allowed
+     * are specified by {@link #getPriorityCallSenders()}.
+     * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
+     */
+    public @State int getPriorityCategoryCalls() {
+        return mPriorityCategories.get(PRIORITY_CATEGORY_CALLS);
+    }
+
+    /**
+     * Whether this policy wants to allow repeat callers (notifications with category
+     * {@link Notification#CATEGORY_CALL} that have recently called) to play sounds and
+     * visually appear or to intercept them when DND is active.
+     * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
+     */
+    public @State int getPriorityCategoryRepeatCallers() {
+        return mPriorityCategories.get(PRIORITY_CATEGORY_REPEAT_CALLERS);
+    }
+
+    /**
+     * Whether this policy wants to allow notifications with category
+     * {@link Notification#CATEGORY_ALARM} to play sounds and visually appear
+     * or to intercept them when DND is active.
+     * When alarms are {@link #STATE_DISALLOW disallowed}, the alarm stream will be muted when DND
+     * is active.
+     * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
+     */
+    public @State int getPriorityCategoryAlarms() {
+        return mPriorityCategories.get(PRIORITY_CATEGORY_ALARMS);
+    }
+
+    /**
+     * Whether this policy wants to allow media notifications to play sounds and visually appear
+     * or to intercept them when DND is active.
+     * When media is {@link #STATE_DISALLOW disallowed}, the media stream will be muted when DND is
+     * active.
+     * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
+     */
+    public @State int getPriorityCategoryMedia() {
+        return mPriorityCategories.get(PRIORITY_CATEGORY_MEDIA);
+    }
+
+    /**
+     * Whether this policy wants to allow system sounds when DND is active.
+     * When system is {@link #STATE_DISALLOW}, the system stream will be muted when DND is active.
+     * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
+     */
+    public @State int getPriorityCategorySystem() {
+        return mPriorityCategories.get(PRIORITY_CATEGORY_SYSTEM);
+    }
+
+    /**
+     * Whether this policy allows {@link Notification#fullScreenIntent full screen intents} from
+     * notifications intercepted by DND.
+     */
+    public @State int getVisualEffectFullScreenIntent() {
+        return mVisualEffects.get(VISUAL_EFFECT_FULL_SCREEN_INTENT);
+    }
+
+    /**
+     * Whether this policy allows {@link NotificationChannel#shouldShowLights() notification
+     * lights} from notifications intercepted by DND.
+     */
+    public @State int getVisualEffectLights() {
+        return mVisualEffects.get(VISUAL_EFFECT_LIGHTS);
+    }
+
+    /**
+     * Whether this policy allows peeking from notifications intercepted by DND.
+     */
+    public @State int getVisualEffectPeek() {
+        return mVisualEffects.get(VISUAL_EFFECT_PEEK);
+    }
+
+    /**
+     * Whether this policy allows notifications intercepted by DND from appearing in the status bar
+     * on devices that support status bars.
+     */
+    public @State int getVisualEffectStatusBar() {
+        return mVisualEffects.get(VISUAL_EFFECT_STATUS_BAR);
+    }
+
+    /**
+     * Whether this policy allows {@link NotificationChannel#canShowBadge() badges} from
+     * notifications intercepted by DND on devices that support badging.
+     */
+    public @State int getVisualEffectBadge() {
+        return mVisualEffects.get(VISUAL_EFFECT_BADGE);
+    }
+
+    /**
+     * Whether this policy allows notifications intercepted by DND from appearing on ambient
+     * displays on devices that support ambient display.
+     */
+    public @State int getVisualEffectAmbient() {
+        return mVisualEffects.get(VISUAL_EFFECT_AMBIENT);
+    }
+
+    /**
+     * Whether this policy allows notifications intercepted by DND from appearing in notification
+     * list views like the notification shade or lockscreen on devices that support those
+     * views.
+     */
+    public @State int getVisualEffectNotificationList() {
+        return mVisualEffects.get(VISUAL_EFFECT_NOTIFICATION_LIST);
+    }
+
+    /**
+     * Builder class for {@link ZenPolicy} objects.
+     * Provides a convenient way to set the various fields of a {@link ZenPolicy}.  If a field
+     * is not set, it is (@link STATE_UNSET} and will not change the current set policy.
+     */
+    public static class Builder {
+        private ZenPolicy mZenPolicy;
+
+        public Builder() {
+            mZenPolicy = new ZenPolicy();
+        }
+
+        /**
+         * Builds the current ZenPolicy.
+         */
+        public ZenPolicy build() {
+            return mZenPolicy.copy();
+        }
+
+        /**
+         * Allows all notifications to bypass DND and unmutes all streams.
+         */
+        public Builder allowAllSounds() {
+            for (int i = 0; i < mZenPolicy.mPriorityCategories.size(); i++) {
+                mZenPolicy.mPriorityCategories.set(i, STATE_ALLOW);
+            }
+            mZenPolicy.mPriorityMessages = PEOPLE_TYPE_ANYONE;
+            mZenPolicy.mPriorityCalls = PEOPLE_TYPE_ANYONE;
+            return this;
+        }
+
+        /**
+         * Intercepts all notifications and prevents them from playing sounds
+         * when DND is active. Also mutes alarm, system and media streams.
+         * Notification channels can still play sounds only if they
+         * {@link NotificationChannel#canBypassDnd can bypass DND}. If no channels can bypass DND,
+         * the ringer stream is also muted.
+         */
+        public Builder disallowAllSounds() {
+            for (int i = 0; i < mZenPolicy.mPriorityCategories.size(); i++) {
+                mZenPolicy.mPriorityCategories.set(i, STATE_DISALLOW);
+            }
+            mZenPolicy.mPriorityMessages = PEOPLE_TYPE_NONE;
+            mZenPolicy.mPriorityCalls = PEOPLE_TYPE_NONE;
+            return this;
+        }
+
+        /**
+         * Allows notifications intercepted by DND to show on all surfaces when DND is active.
+         */
+        public Builder showAllVisualEffects() {
+            for (int i = 0; i < mZenPolicy.mVisualEffects.size(); i++) {
+                mZenPolicy.mVisualEffects.set(i, STATE_ALLOW);
+            }
+            return this;
+        }
+
+        /**
+         * Disallows notifications intercepted by DND from showing when DND is active.
+         */
+        public Builder hideAllVisualEffects() {
+            for (int i = 0; i < mZenPolicy.mVisualEffects.size(); i++) {
+                mZenPolicy.mVisualEffects.set(i, STATE_DISALLOW);
+            }
+            return this;
+        }
+
+        /**
+         * Unsets a priority category, neither allowing or disallowing. When applying this policy,
+         * unset categories will default to the current applied policy.
+         * @hide
+         */
+        public Builder unsetPriorityCategory(@PriorityCategory int category) {
+            mZenPolicy.mPriorityCategories.set(category, STATE_UNSET);
+
+            if (category == PRIORITY_CATEGORY_MESSAGES) {
+                mZenPolicy.mPriorityMessages = STATE_UNSET;
+            } else if (category == PRIORITY_CATEGORY_CALLS) {
+                mZenPolicy.mPriorityCalls = STATE_UNSET;
+            }
+
+            return this;
+        }
+
+        /**
+         * Unsets a visual effect, neither allowing or disallowing. When applying this policy,
+         * unset effects will default to the current applied policy.
+         * @hide
+         */
+        public Builder unsetVisualEffect(@VisualEffect int effect) {
+            mZenPolicy.mVisualEffects.set(effect, STATE_UNSET);
+            return this;
+        }
+
+        /**
+         * Whether to allow notifications with category {@link Notification#CATEGORY_REMINDER}
+         * to play sounds and visually appear or to intercept them when DND is active.
+         */
+        public Builder allowReminders(boolean allow) {
+            mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_REMINDERS,
+                    allow ? STATE_ALLOW : STATE_DISALLOW);
+            return this;
+        }
+
+        /**
+         * Whether to allow notifications with category {@link Notification#CATEGORY_EVENT}
+         * to play sounds and visually appear or to intercept them when DND is active.
+         */
+        public Builder allowEvents(boolean allow) {
+            mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_EVENTS,
+                    allow ? STATE_ALLOW : STATE_DISALLOW);
+            return this;
+        }
+
+        /**
+         * Whether to allow notifications with category {@link Notification#CATEGORY_MESSAGE}
+         * that match audienceType to play sounds and visually appear or to intercept
+         * them when DND is active.
+         * @param audienceType message senders that are allowed to bypass DND
+         */
+        public Builder allowMessages(@PeopleType int audienceType) {
+            if (audienceType == STATE_UNSET) {
+                return unsetPriorityCategory(PRIORITY_CATEGORY_MESSAGES);
+            }
+
+            if (audienceType == PEOPLE_TYPE_NONE) {
+                mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_MESSAGES, STATE_DISALLOW);
+            } else if (audienceType == PEOPLE_TYPE_ANYONE || audienceType == PEOPLE_TYPE_CONTACTS
+                    || audienceType == PEOPLE_TYPE_STARRED) {
+                mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_MESSAGES, STATE_ALLOW);
+            } else {
+                return this;
+            }
+
+            mZenPolicy.mPriorityMessages = audienceType;
+            return this;
+        }
+
+        /**
+         * Whether to allow notifications with category {@link Notification#CATEGORY_CALL}
+         * that match audienceType to play sounds and visually appear or to intercept
+         * them when DND is active.
+         * @param audienceType callers that are allowed to bypass DND
+         */
+        public Builder allowCalls(@PeopleType int audienceType) {
+            if (audienceType == STATE_UNSET) {
+                return unsetPriorityCategory(PRIORITY_CATEGORY_CALLS);
+            }
+
+            if (audienceType == PEOPLE_TYPE_NONE) {
+                mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_CALLS, STATE_DISALLOW);
+            } else if (audienceType == PEOPLE_TYPE_ANYONE || audienceType == PEOPLE_TYPE_CONTACTS
+                    || audienceType == PEOPLE_TYPE_STARRED) {
+                mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_CALLS, STATE_ALLOW);
+            } else {
+                return this;
+            }
+
+            mZenPolicy.mPriorityCalls = audienceType;
+            return this;
+        }
+
+        /**
+         * Whether to allow repeat callers (notifications with category
+         * {@link Notification#CATEGORY_CALL} that have recently called
+         * to play sounds and visually appear.
+         */
+        public Builder allowRepeatCallers(boolean allow) {
+            mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_REPEAT_CALLERS,
+                    allow ? STATE_ALLOW : STATE_DISALLOW);
+            return this;
+        }
+
+
+        /**
+         * Whether to allow notifications with category {@link Notification#CATEGORY_ALARM}
+         * to play sounds and visually appear or to intercept them when DND is active.
+         * Disallowing alarms will mute the alarm stream when DND is active.
+         */
+        public Builder allowAlarms(boolean allow) {
+            mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_ALARMS,
+                    allow ? STATE_ALLOW : STATE_DISALLOW);
+            return this;
+        }
+
+        /**
+         * Whether to allow media notifications to play sounds and visually
+         * appear or to intercept them when DND is active.
+         * Disallowing media will mute the media stream when DND is active.
+         */
+        public Builder allowMedia(boolean allow) {
+            mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_MEDIA,
+                    allow ? STATE_ALLOW : STATE_DISALLOW);
+            return this;
+        }
+
+        /**
+         * Whether to allow system sounds to play when DND is active.
+         * Disallowing system sounds will mute the system stream when DND is active.
+         */
+        public Builder allowSystem(boolean allow) {
+            mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_SYSTEM,
+                    allow ? STATE_ALLOW : STATE_DISALLOW);
+            return this;
+        }
+
+        /**
+         * Whether {@link Notification#fullScreenIntent full screen intents} that are intercepted
+         * by DND are shown.
+         */
+        public Builder showFullScreenIntent(boolean show) {
+            mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_FULL_SCREEN_INTENT,
+                    show ? STATE_ALLOW : STATE_DISALLOW);
+            return this;
+        }
+
+        /**
+         * Whether {@link NotificationChannel#shouldShowLights() notification lights} from
+         * notifications intercepted by DND are blocked.
+         */
+        public Builder showLights(boolean show) {
+            mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_LIGHTS,
+                    show ? STATE_ALLOW : STATE_DISALLOW);
+            return this;
+        }
+
+        /**
+         * Whether notifications intercepted by DND are prevented from peeking.
+         */
+        public Builder showPeeking(boolean show) {
+            mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_PEEK,
+                    show ? STATE_ALLOW : STATE_DISALLOW);
+            return this;
+        }
+
+        /**
+         * Whether notifications intercepted by DND are prevented from appearing in the status bar
+         * on devices that support status bars.
+         */
+        public Builder showStatusBarIcons(boolean show) {
+            mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_STATUS_BAR,
+                    show ? STATE_ALLOW : STATE_DISALLOW);
+            return this;
+        }
+
+        /**
+         * Whether {@link NotificationChannel#canShowBadge() badges} from
+         * notifications intercepted by DND are allowed on devices that support badging.
+         */
+        public Builder showBadges(boolean show) {
+            mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_BADGE,
+                    show ? STATE_ALLOW : STATE_DISALLOW);
+            return this;
+        }
+
+        /**
+         * Whether notification intercepted by DND are prevented from appearing on ambient displays
+         * on devices that support ambient display.
+         */
+        public Builder showInAmbientDisplay(boolean show) {
+            mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_AMBIENT,
+                    show ? STATE_ALLOW : STATE_DISALLOW);
+            return this;
+        }
+
+        /**
+         * Whether notification intercepted by DND are prevented from appearing in notification
+         * list views like the notification shade or lockscreen on devices that support those
+         * views.
+         */
+        public Builder showInNotificationList(boolean show) {
+            mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_NOTIFICATION_LIST,
+                    show ? STATE_ALLOW : STATE_DISALLOW);
+            return this;
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeList(mPriorityCategories);
+        dest.writeList(mVisualEffects);
+        dest.writeInt(mPriorityCalls);
+        dest.writeInt(mPriorityMessages);
+    }
+
+    public static final Parcelable.Creator<ZenPolicy> CREATOR =
+            new Parcelable.Creator<ZenPolicy>() {
+        @Override
+        public ZenPolicy createFromParcel(Parcel source) {
+            ZenPolicy policy = new ZenPolicy();
+            policy.mPriorityCategories = source.readArrayList(Integer.class.getClassLoader());
+            policy.mVisualEffects = source.readArrayList(Integer.class.getClassLoader());
+            policy.mPriorityCalls = source.readInt();
+            policy.mPriorityMessages = source.readInt();
+            return policy;
+        }
+
+        @Override
+        public ZenPolicy[] newArray(int size) {
+            return new ZenPolicy[size];
+        }
+    };
+
+    @Override
+    public String toString() {
+        return new StringBuilder(ZenPolicy.class.getSimpleName())
+                .append('{')
+                .append("priorityCategories=[").append(priorityCategoriesToString())
+                .append("], visualEffects=[").append(visualEffectsToString())
+                .append(", priorityCalls=").append(stateToString(mPriorityCalls))
+                .append("], priorityMessages=").append(stateToString(mPriorityMessages))
+                .append('}')
+                .toString();
+    }
+
+
+    private String priorityCategoriesToString() {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 0; i < mPriorityCategories.size(); i++) {
+            if (mPriorityCategories.get(i) != STATE_UNSET) {
+                builder.append(indexToCategory(i))
+                        .append("=")
+                        .append(stateToString(mPriorityCategories.get(i)))
+                        .append(" ");
+            }
+
+        }
+        return builder.toString();
+    }
+
+    private String visualEffectsToString() {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 0; i < mVisualEffects.size(); i++) {
+            if (mVisualEffects.get(i) != STATE_UNSET) {
+                builder.append(indexToVisualEffect(i))
+                        .append("=")
+                        .append(stateToString(mVisualEffects.get(i)))
+                        .append(" ");
+            }
+
+        }
+        return builder.toString();
+    }
+
+    private String indexToVisualEffect(@VisualEffect int visualEffectIndex) {
+        switch (visualEffectIndex) {
+            case VISUAL_EFFECT_FULL_SCREEN_INTENT:
+                return "fullScreenIntent";
+            case VISUAL_EFFECT_LIGHTS:
+                return "lights";
+            case VISUAL_EFFECT_PEEK:
+                return "peek";
+            case VISUAL_EFFECT_STATUS_BAR:
+                return "statusBar";
+            case VISUAL_EFFECT_BADGE:
+                return "badge";
+            case VISUAL_EFFECT_AMBIENT:
+                return "ambient";
+            case VISUAL_EFFECT_NOTIFICATION_LIST:
+                return "notificationList";
+        }
+        return null;
+    }
+
+    private String indexToCategory(@PriorityCategory int categoryIndex) {
+        switch (categoryIndex) {
+            case PRIORITY_CATEGORY_REMINDERS:
+                return "reminders";
+            case PRIORITY_CATEGORY_EVENTS:
+                return "events";
+            case PRIORITY_CATEGORY_MESSAGES:
+                return "messages";
+            case PRIORITY_CATEGORY_CALLS:
+                return "calls";
+            case PRIORITY_CATEGORY_REPEAT_CALLERS:
+                return "repeatCallers";
+            case PRIORITY_CATEGORY_ALARMS:
+                return "alarms";
+            case PRIORITY_CATEGORY_MEDIA:
+                return "media";
+            case PRIORITY_CATEGORY_SYSTEM:
+                return "system";
+        }
+        return null;
+    }
+
+    private String stateToString(@State int state) {
+        switch (state) {
+            case STATE_UNSET:
+                return "unset";
+            case STATE_DISALLOW:
+                return "disallow";
+            case STATE_ALLOW:
+                return "allow";
+        }
+        return null;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof ZenPolicy)) return false;
+        if (o == this) return true;
+        final ZenPolicy other = (ZenPolicy) o;
+
+        return Objects.equals(other.mPriorityCategories, mPriorityCategories)
+                && Objects.equals(other.mVisualEffects, mVisualEffects)
+                && other.mPriorityCalls == mPriorityCalls
+                && other.mPriorityMessages == mPriorityMessages;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mPriorityCategories, mVisualEffects, mPriorityCalls, mPriorityMessages);
+    }
+
+    private @ZenPolicy.State int getZenPolicyPriorityCategoryState(@PriorityCategory int
+            category) {
+        switch (category) {
+            case PRIORITY_CATEGORY_REMINDERS:
+                return getPriorityCategoryReminders();
+            case PRIORITY_CATEGORY_EVENTS:
+                return getPriorityCategoryEvents();
+            case PRIORITY_CATEGORY_MESSAGES:
+                return getPriorityCategoryMessages();
+            case PRIORITY_CATEGORY_CALLS:
+                return getPriorityCategoryCalls();
+            case PRIORITY_CATEGORY_REPEAT_CALLERS:
+                return getPriorityCategoryRepeatCallers();
+            case PRIORITY_CATEGORY_ALARMS:
+                return getPriorityCategoryAlarms();
+            case PRIORITY_CATEGORY_MEDIA:
+                return getPriorityCategoryMedia();
+            case PRIORITY_CATEGORY_SYSTEM:
+                return getPriorityCategorySystem();
+        }
+        return -1;
+    }
+
+    private @ZenPolicy.State int getZenPolicyVisualEffectState(@VisualEffect int effect) {
+        switch (effect) {
+            case VISUAL_EFFECT_FULL_SCREEN_INTENT:
+                return getVisualEffectFullScreenIntent();
+            case VISUAL_EFFECT_LIGHTS:
+                return getVisualEffectLights();
+            case VISUAL_EFFECT_PEEK:
+                return getVisualEffectPeek();
+            case VISUAL_EFFECT_STATUS_BAR:
+                return getVisualEffectStatusBar();
+            case VISUAL_EFFECT_BADGE:
+                return getVisualEffectBadge();
+            case VISUAL_EFFECT_AMBIENT:
+                return getVisualEffectAmbient();
+            case VISUAL_EFFECT_NOTIFICATION_LIST:
+                return getVisualEffectNotificationList();
+        }
+        return -1;
+    }
+
+    /** @hide */
+    public boolean isCategoryAllowed(@PriorityCategory int category, boolean defaultVal) {
+        switch (getZenPolicyPriorityCategoryState(category)) {
+            case ZenPolicy.STATE_ALLOW:
+                return true;
+            case ZenPolicy.STATE_DISALLOW:
+                return false;
+            default:
+                return defaultVal;
+        }
+    }
+
+    /** @hide */
+    public boolean isVisualEffectAllowed(@VisualEffect int effect, boolean defaultVal) {
+        switch (getZenPolicyVisualEffectState(effect)) {
+            case ZenPolicy.STATE_ALLOW:
+                return true;
+            case ZenPolicy.STATE_DISALLOW:
+                return false;
+            default:
+                return defaultVal;
+        }
+    }
+
+    /**
+     * Applies another policy on top of this policy
+     * @hide
+     */
+    public void apply(ZenPolicy policyToApply) {
+        // apply priority categories
+        for (int category = 0; category < mPriorityCategories.size(); category++) {
+            if (mPriorityCategories.get(category) == STATE_DISALLOW) {
+                // if a priority category is already disallowed by the policy, cannot allow
+                continue;
+            }
+
+            @State int newState = policyToApply.mPriorityCategories.get(category);
+            if (newState != STATE_UNSET) {
+                mPriorityCategories.set(category, newState);
+
+                if (category == PRIORITY_CATEGORY_MESSAGES
+                        && mPriorityMessages < policyToApply.mPriorityMessages) {
+                    mPriorityMessages = policyToApply.mPriorityMessages;
+                } else if (category == PRIORITY_CATEGORY_CALLS
+                        && mPriorityCalls < policyToApply.mPriorityCalls) {
+                    mPriorityCalls = policyToApply.mPriorityCalls;
+                }
+            }
+        }
+
+        // apply visual effects
+        for (int visualEffect = 0; visualEffect < mVisualEffects.size(); visualEffect++) {
+            if (mVisualEffects.get(visualEffect) == STATE_DISALLOW) {
+                // if a visual effect is already disallowed by the policy, cannot allow
+                continue;
+            }
+
+            if (policyToApply.mVisualEffects.get(visualEffect) != STATE_UNSET) {
+                mVisualEffects.set(visualEffect, policyToApply.mVisualEffects.get(visualEffect));
+            }
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+
+        proto.write(ZenPolicyProto.REMINDERS, getPriorityCategoryReminders());
+        proto.write(ZenPolicyProto.EVENTS, getPriorityCategoryEvents());
+        proto.write(ZenPolicyProto.MESSAGES, getPriorityCategoryMessages());
+        proto.write(ZenPolicyProto.CALLS, getPriorityCategoryCalls());
+        proto.write(ZenPolicyProto.REPEAT_CALLERS, getPriorityCategoryRepeatCallers());
+        proto.write(ZenPolicyProto.ALARMS, getPriorityCategoryAlarms());
+        proto.write(ZenPolicyProto.MEDIA, getPriorityCategoryMedia());
+        proto.write(ZenPolicyProto.SYSTEM, getPriorityCategorySystem());
+
+        proto.write(ZenPolicyProto.FULL_SCREEN_INTENT, getVisualEffectFullScreenIntent());
+        proto.write(ZenPolicyProto.LIGHTS, getVisualEffectLights());
+        proto.write(ZenPolicyProto.PEEK, getVisualEffectPeek());
+        proto.write(ZenPolicyProto.STATUS_BAR, getVisualEffectStatusBar());
+        proto.write(ZenPolicyProto.BADGE, getVisualEffectBadge());
+        proto.write(ZenPolicyProto.AMBIENT, getVisualEffectAmbient());
+        proto.write(ZenPolicyProto.NOTIFICATION_LIST, getVisualEffectNotificationList());
+
+        proto.write(ZenPolicyProto.PRIORITY_MESSAGES, getPriorityMessageSenders());
+        proto.write(ZenPolicyProto.PRIORITY_CALLS, getPriorityCallSenders());
+        proto.end(token);
+    }
+
+    /**
+     * Makes deep copy of this ZenPolicy.
+     * @hide
+     */
+    public ZenPolicy copy() {
+        final Parcel parcel = Parcel.obtain();
+        try {
+            writeToParcel(parcel, 0);
+            parcel.setDataPosition(0);
+            return CREATOR.createFromParcel(parcel);
+        } finally {
+            parcel.recycle();
+        }
+    }
+}
diff --git a/core/java/android/service/voice/IVoiceInteractionService.aidl b/core/java/android/service/voice/IVoiceInteractionService.aidl
index e3d68a6..24819a6 100644
--- a/core/java/android/service/voice/IVoiceInteractionService.aidl
+++ b/core/java/android/service/voice/IVoiceInteractionService.aidl
@@ -16,6 +16,8 @@
 
 package android.service.voice;
 
+import com.android.internal.app.IVoiceActionCheckCallback;
+
 /**
  * @hide
  */
@@ -24,4 +26,6 @@
     void soundModelsChanged();
     void shutdown();
     void launchVoiceAssistFromKeyguard();
+    void getActiveServiceSupportedActions(in List<String> voiceActions,
+     in IVoiceActionCheckCallback callback);
 }
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 0bbc07e..e105fdf 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -16,6 +16,8 @@
 
 package android.service.voice;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.UnsupportedAppUsage;
 import android.app.Service;
@@ -26,17 +28,22 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.provider.Settings;
+import android.util.ArraySet;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.IVoiceActionCheckCallback;
 import com.android.internal.app.IVoiceInteractionManagerService;
+import com.android.internal.util.function.pooled.PooledLambda;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Locale;
+import java.util.Set;
 
 /**
  * Top-level service of the current global voice interactor, which is providing
@@ -71,23 +78,43 @@
     public static final String SERVICE_META_DATA = "android.voice_interaction";
 
     IVoiceInteractionService mInterface = new IVoiceInteractionService.Stub() {
-        @Override public void ready() {
-            mHandler.sendEmptyMessage(MSG_READY);
-        }
-        @Override public void shutdown() {
-            mHandler.sendEmptyMessage(MSG_SHUTDOWN);
-        }
-        @Override public void soundModelsChanged() {
-            mHandler.sendEmptyMessage(MSG_SOUND_MODELS_CHANGED);
-        }
         @Override
-        public void launchVoiceAssistFromKeyguard() throws RemoteException {
-            mHandler.sendEmptyMessage(MSG_LAUNCH_VOICE_ASSIST_FROM_KEYGUARD);
+        public void ready() {
+            Handler.getMain().executeOrSendMessage(PooledLambda.obtainMessage(
+                    VoiceInteractionService::onReady, VoiceInteractionService.this));
+        }
+
+        @Override
+        public void shutdown() {
+            Handler.getMain().executeOrSendMessage(PooledLambda.obtainMessage(
+                    VoiceInteractionService::onShutdownInternal, VoiceInteractionService.this));
+        }
+
+        @Override
+        public void soundModelsChanged() {
+            Handler.getMain().executeOrSendMessage(PooledLambda.obtainMessage(
+                    VoiceInteractionService::onSoundModelsChangedInternal,
+                    VoiceInteractionService.this));
+        }
+
+        @Override
+        public void launchVoiceAssistFromKeyguard() {
+            Handler.getMain().executeOrSendMessage(PooledLambda.obtainMessage(
+                    VoiceInteractionService::onLaunchVoiceAssistFromKeyguard,
+                    VoiceInteractionService.this));
+        }
+
+        @Override
+        public void getActiveServiceSupportedActions(List<String> voiceActions,
+                IVoiceActionCheckCallback callback) {
+            Handler.getMain().executeOrSendMessage(
+                    PooledLambda.obtainMessage(VoiceInteractionService::onHandleVoiceActionCheck,
+                            VoiceInteractionService.this,
+                            voiceActions,
+                            callback));
         }
     };
 
-    MyHandler mHandler;
-
     IVoiceInteractionManagerService mSystemService;
 
     private final Object mLock = new Object();
@@ -96,33 +123,6 @@
 
     private AlwaysOnHotwordDetector mHotwordDetector;
 
-    static final int MSG_READY = 1;
-    static final int MSG_SHUTDOWN = 2;
-    static final int MSG_SOUND_MODELS_CHANGED = 3;
-    static final int MSG_LAUNCH_VOICE_ASSIST_FROM_KEYGUARD = 4;
-
-    class MyHandler extends Handler {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_READY:
-                    onReady();
-                    break;
-                case MSG_SHUTDOWN:
-                    onShutdownInternal();
-                    break;
-                case MSG_SOUND_MODELS_CHANGED:
-                    onSoundModelsChangedInternal();
-                    break;
-                case MSG_LAUNCH_VOICE_ASSIST_FROM_KEYGUARD:
-                    onLaunchVoiceAssistFromKeyguard();
-                    break;
-                default:
-                    super.handleMessage(msg);
-            }
-        }
-    }
-
     /**
      * Called when a user has activated an affordance to launch voice assist from the Keyguard.
      *
@@ -186,7 +186,7 @@
      * be any combination of
      * {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST} and
      * {@link VoiceInteractionSession#SHOW_WITH_SCREENSHOT
-      * VoiceInteractionSession.SHOW_WITH_SCREENSHOT}
+     * VoiceInteractionSession.SHOW_WITH_SCREENSHOT}
      * to request that the system generate and deliver assist data on the current foreground
      * app as part of showing the session UI.
      */
@@ -200,10 +200,22 @@
         }
     }
 
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        mHandler = new MyHandler();
+    /**
+     * Request to query for what extended voice actions this service supports. This method will
+     * be called when the system checks the supported actions of this
+     * {@link VoiceInteractionService}. Supported actions may be delivered to
+     * {@link VoiceInteractionSession} later to request a session to perform an action.
+     *
+     * <p>Voice actions are defined in support libraries and could vary based on platform context.
+     * For example, car related voice actions will be defined in car support libraries.
+     *
+     * @param voiceActions A set of checked voice actions.
+     * @return Returns a subset of checked voice actions. Additional voice actions in the
+     * returned set will be ignored. Returns null or empty set if no actions are supported.
+     */
+    @Nullable
+    public Set<String> onGetSupportedVoiceActions(@NonNull Set<String> voiceActions) {
+        return null;
     }
 
     @Override
@@ -254,6 +266,18 @@
         }
     }
 
+    private void onHandleVoiceActionCheck(List<String> voiceActions,
+            IVoiceActionCheckCallback callback) {
+        if (callback != null) {
+            try {
+                Set<String> voiceActionsSet = new ArraySet<>(voiceActions);
+                Set<String> resultSet = onGetSupportedVoiceActions(voiceActionsSet);
+                callback.onComplete(resultSet == null ? null : new ArrayList<>(resultSet));
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
     /**
      * Creates an {@link AlwaysOnHotwordDetector} for the given keyphrase and locale.
      * This instance must be retained and used by the client.
@@ -289,12 +313,12 @@
     }
 
     /**
-      * Checks if a given keyphrase and locale are supported to create an
-      * {@link AlwaysOnHotwordDetector}.
-      *
-      * @return true if the keyphrase and locale combination is supported, false otherwise.
-      * @hide
-      */
+     * Checks if a given keyphrase and locale are supported to create an
+     * {@link AlwaysOnHotwordDetector}.
+     *
+     * @return true if the keyphrase and locale combination is supported, false otherwise.
+     * @hide
+     */
     @UnsupportedAppUsage
     public final boolean isKeyphraseAndLocaleSupportedForHotword(String keyphrase, Locale locale) {
         if (mKeyphraseEnrollmentInfo == null) {
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 26223f7..163e3d5 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -115,6 +115,12 @@
      */
     public static final int SHOW_SOURCE_PUSH_TO_TALK = 1 << 5;
 
+    /**
+     * Flag for use with {@link #onShow}: indicates that the voice interaction service was invoked
+     * from a notification.
+     */
+    public static final int SHOW_SOURCE_NOTIFICATION = 1 << 6;
+
     final Context mContext;
     final HandlerCaller mHandlerCaller;
 
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index c46c831..c928da1 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -23,6 +23,7 @@
 import android.annotation.UnsupportedAppUsage;
 import android.graphics.Paint;
 import android.graphics.Rect;
+import android.os.Build;
 import android.text.style.ReplacementSpan;
 import android.text.style.UpdateLayout;
 import android.text.style.WrapTogetherSpan;
@@ -354,7 +355,7 @@
      * @deprecated Use {@link Builder} instead.
      */
     @Deprecated
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public DynamicLayout(@NonNull CharSequence base, @NonNull CharSequence display,
                          @NonNull TextPaint paint,
                          @IntRange(from = 0) int width,
diff --git a/core/java/android/text/GraphicsOperations.java b/core/java/android/text/GraphicsOperations.java
index 6edf845..6c15446 100644
--- a/core/java/android/text/GraphicsOperations.java
+++ b/core/java/android/text/GraphicsOperations.java
@@ -58,6 +58,6 @@
     /**
      * Just like {@link Paint#getTextRunCursor}.
      */
-    int getTextRunCursor(int contextStart, int contextEnd, int dir, int offset,
+    int getTextRunCursor(int contextStart, int contextEnd, boolean isRtl, int offset,
             int cursorOpt, Paint p);
 }
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 33c977b..c89617f 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -619,7 +619,7 @@
                     previousLineBottom = lbottom;
                     int lbaseline = lbottom - getLineDescent(i);
 
-                    if (start >= spanEnd) {
+                    if (end >= spanEnd) {
                         // These should be infrequent, so we'll use this so that
                         // we don't have to check as often.
                         spanEnd = mLineBackgroundSpans.getNextTransition(start, textLength);
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index 9d841e8..0d29da0 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -1551,7 +1551,7 @@
      *
      * @param contextStart the start index of the context
      * @param contextEnd the (non-inclusive) end index of the context
-     * @param dir either DIRECTION_RTL or DIRECTION_LTR
+     * @param dir 1 if the run is RTL, otherwise 0
      * @param offset the cursor position to move from
      * @param cursorOpt how to move the cursor, one of CURSOR_AFTER,
      * CURSOR_AT_OR_AFTER, CURSOR_BEFORE,
@@ -1563,21 +1563,28 @@
     @Deprecated
     public int getTextRunCursor(int contextStart, int contextEnd, int dir, int offset,
             int cursorOpt, Paint p) {
+        return getTextRunCursor(contextStart, contextEnd, dir == 1, offset, cursorOpt, p);
+    }
+
+    /** @hide */
+    @Override
+    public int getTextRunCursor(int contextStart, int contextEnd, boolean isRtl, int offset,
+            int cursorOpt, Paint p) {
 
         int ret;
 
         int contextLen = contextEnd - contextStart;
         if (contextEnd <= mGapStart) {
             ret = p.getTextRunCursor(mText, contextStart, contextLen,
-                    dir, offset, cursorOpt);
+                    isRtl, offset, cursorOpt);
         } else if (contextStart >= mGapStart) {
             ret = p.getTextRunCursor(mText, contextStart + mGapLength, contextLen,
-                    dir, offset + mGapLength, cursorOpt) - mGapLength;
+                    isRtl, offset + mGapLength, cursorOpt) - mGapLength;
         } else {
             char[] buf = TextUtils.obtain(contextLen);
             getChars(contextStart, contextEnd, buf, 0);
             ret = p.getTextRunCursor(buf, 0, contextLen,
-                    dir, offset - contextStart, cursorOpt) + contextStart;
+                    isRtl, offset - contextStart, cursorOpt) + contextStart;
             TextUtils.recycle(buf);
         }
 
@@ -1603,13 +1610,14 @@
     public boolean equals(Object o) {
         if (o instanceof Spanned &&
                 toString().equals(o.toString())) {
-            Spanned other = (Spanned) o;
+            final Spanned other = (Spanned) o;
             // Check span data
-            Object[] otherSpans = other.getSpans(0, other.length(), Object.class);
+            final Object[] otherSpans = other.getSpans(0, other.length(), Object.class);
+            final Object[] thisSpans = getSpans(0, length(), Object.class);
             if (mSpanCount == otherSpans.length) {
                 for (int i = 0; i < mSpanCount; ++i) {
-                    Object thisSpan = mSpans[i];
-                    Object otherSpan = otherSpans[i];
+                    final Object thisSpan = thisSpans[i];
+                    final Object otherSpan = otherSpans[i];
                     if (thisSpan == this) {
                         if (other != otherSpan ||
                                 getSpanStart(thisSpan) != other.getSpanStart(otherSpan) ||
diff --git a/core/java/android/text/SpannableStringInternal.java b/core/java/android/text/SpannableStringInternal.java
index 7acd539..a986633 100644
--- a/core/java/android/text/SpannableStringInternal.java
+++ b/core/java/android/text/SpannableStringInternal.java
@@ -16,12 +16,13 @@
 
 package android.text;
 
+import android.annotation.UnsupportedAppUsage;
+
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.GrowingArrayUtils;
 
 import libcore.util.EmptyArray;
 
-import android.annotation.UnsupportedAppUsage;
 import java.lang.reflect.Array;
 
 /* package */ abstract class SpannableStringInternal
@@ -502,13 +503,14 @@
     public boolean equals(Object o) {
         if (o instanceof Spanned &&
                 toString().equals(o.toString())) {
-            Spanned other = (Spanned) o;
+            final Spanned other = (Spanned) o;
             // Check span data
-            Object[] otherSpans = other.getSpans(0, other.length(), Object.class);
+            final Object[] otherSpans = other.getSpans(0, other.length(), Object.class);
+            final Object[] thisSpans = getSpans(0, length(), Object.class);
             if (mSpanCount == otherSpans.length) {
                 for (int i = 0; i < mSpanCount; ++i) {
-                    Object thisSpan = mSpans[i];
-                    Object otherSpan = otherSpans[i];
+                    final Object thisSpan = thisSpans[i];
+                    final Object otherSpan = otherSpans[i];
                     if (thisSpan == this) {
                         if (other != otherSpan ||
                                 getSpanStart(thisSpan) != other.getSpanStart(otherSpan) ||
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 5adb1ca..e1ffef0 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -22,6 +22,7 @@
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.graphics.Paint;
+import android.os.Build;
 import android.text.style.LeadingMarginSpan;
 import android.text.style.LeadingMarginSpan.LeadingMarginSpan2;
 import android.text.style.LineHeightSpan;
@@ -1293,7 +1294,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public int getHeight(boolean cap) {
         if (cap && mLineCount > mMaximumVisibleLineCount && mMaxLineHeight == -1
                 && Log.isLoggable(TAG, Log.WARN)) {
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index bf2d600..44dfd11 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -22,6 +22,7 @@
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Paint.FontMetricsInt;
+import android.os.Build;
 import android.text.Layout.Directions;
 import android.text.Layout.TabStops;
 import android.text.style.CharacterStyle;
@@ -61,7 +62,7 @@
     private TabStops mTabs;
     private char[] mChars;
     private boolean mCharsValid;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private Spanned mSpanned;
     private PrecomputedText mComputed;
 
@@ -801,14 +802,13 @@
             }
         }
 
-        int dir = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR;
         int cursorOpt = after ? Paint.CURSOR_AFTER : Paint.CURSOR_BEFORE;
         if (mCharsValid) {
             return wp.getTextRunCursor(mChars, spanStart, spanLimit - spanStart,
-                    dir, offset, cursorOpt);
+                    runIsRtl, offset, cursorOpt);
         } else {
             return wp.getTextRunCursor(mText, mStart + spanStart,
-                    mStart + spanLimit, dir, mStart + offset, cursorOpt) - mStart;
+                    mStart + spanLimit, runIsRtl, mStart + offset, cursorOpt) - mStart;
         }
     }
 
@@ -1230,7 +1230,7 @@
                     // with the next chunk. So we just save the TextPaint for future comparisons
                     // and use.
                     activePaint.set(wp);
-                } else if (!wp.hasEqualAttributes(activePaint)) {
+                } else if (!equalAttributes(wp, activePaint)) {
                     // The style of the present chunk of text is substantially different from the
                     // style of the previous chunk. We need to handle the active piece of text
                     // and restart with the present chunk.
@@ -1335,4 +1335,42 @@
     }
 
     private static final int TAB_INCREMENT = 20;
+
+    private static boolean equalAttributes(@NonNull TextPaint lp, @NonNull TextPaint rp) {
+        return lp.getColorFilter() == rp.getColorFilter()
+                && lp.getMaskFilter() == rp.getMaskFilter()
+                && lp.getShader() == rp.getShader()
+                && lp.getTypeface() == rp.getTypeface()
+                && lp.getXfermode() == rp.getXfermode()
+                && lp.getTextLocales().equals(rp.getTextLocales())
+                && TextUtils.equals(lp.getFontFeatureSettings(), rp.getFontFeatureSettings())
+                && TextUtils.equals(lp.getFontVariationSettings(), rp.getFontVariationSettings())
+                && lp.getShadowLayerRadius() == rp.getShadowLayerRadius()
+                && lp.getShadowLayerDx() == rp.getShadowLayerDx()
+                && lp.getShadowLayerDy() == rp.getShadowLayerDy()
+                && lp.getShadowLayerColor() == rp.getShadowLayerColor()
+                && lp.getFlags() == rp.getFlags()
+                && lp.getHinting() == rp.getHinting()
+                && lp.getStyle() == rp.getStyle()
+                && lp.getColor() == rp.getColor()
+                && lp.getStrokeWidth() == rp.getStrokeWidth()
+                && lp.getStrokeMiter() == rp.getStrokeMiter()
+                && lp.getStrokeCap() == rp.getStrokeCap()
+                && lp.getStrokeJoin() == rp.getStrokeJoin()
+                && lp.getTextAlign() == rp.getTextAlign()
+                && lp.isElegantTextHeight() == rp.isElegantTextHeight()
+                && lp.getTextSize() == rp.getTextSize()
+                && lp.getTextScaleX() == rp.getTextScaleX()
+                && lp.getTextSkewX() == rp.getTextSkewX()
+                && lp.getLetterSpacing() == rp.getLetterSpacing()
+                && lp.getWordSpacing() == rp.getWordSpacing()
+                && lp.getHyphenEdit() == rp.getHyphenEdit()
+                && lp.bgColor == rp.bgColor
+                && lp.baselineShift == rp.baselineShift
+                && lp.linkColor == rp.linkColor
+                && lp.drawableState == rp.drawableState
+                && lp.density == rp.density
+                && lp.underlineColor == rp.underlineColor
+                && lp.underlineThickness == rp.underlineThickness;
+    }
 }
diff --git a/core/java/android/text/TextPaint.java b/core/java/android/text/TextPaint.java
index 7bcc685..d5aad33 100644
--- a/core/java/android/text/TextPaint.java
+++ b/core/java/android/text/TextPaint.java
@@ -17,7 +17,7 @@
 package android.text;
 
 import android.annotation.ColorInt;
-import android.annotation.NonNull;
+import android.annotation.Px;
 import android.annotation.UnsupportedAppUsage;
 import android.graphics.Paint;
 
@@ -37,17 +37,14 @@
     public float density = 1.0f;
     /**
      * Special value 0 means no custom underline
-     * @hide
      */
     @ColorInt
-    @UnsupportedAppUsage
     public int underlineColor = 0;
+
     /**
      * Thickness of the underline, in pixels.
-     * @hide
      */
-    @UnsupportedAppUsage
-    public float underlineThickness;
+    public @Px float underlineThickness;
 
     public TextPaint() {
         super();
@@ -78,24 +75,6 @@
     }
 
     /**
-     * Returns true if all attributes, including the attributes inherited from Paint, are equal.
-     *
-     * The caller is expected to have checked the trivial cases, like the pointers being equal,
-     * the objects having different classes, or the parameter being null.
-     * @hide
-     */
-    public boolean hasEqualAttributes(@NonNull TextPaint other) {
-        return bgColor == other.bgColor
-                && baselineShift == other.baselineShift
-                && linkColor == other.linkColor
-                && drawableState == other.drawableState
-                && density == other.density
-                && underlineColor == other.underlineColor
-                && underlineThickness == other.underlineThickness
-                && super.hasEqualAttributes((Paint) other);
-    }
-
-    /**
      * Defines a custom underline for this Paint.
      * @param color underline solid color
      * @param thickness underline thickness
diff --git a/core/java/android/text/TextWatcher.java b/core/java/android/text/TextWatcher.java
index bad09f2..a0aef69 100644
--- a/core/java/android/text/TextWatcher.java
+++ b/core/java/android/text/TextWatcher.java
@@ -17,7 +17,7 @@
 package android.text;
 
 /**
- * When an object of a type is attached to an Editable, its methods will
+ * When an object of this type is attached to an Editable, its methods will
  * be called when the text is changed.
  */
 public interface TextWatcher extends NoCopySpan {
diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java
index 5f0a46d..d4bcd12 100644
--- a/core/java/android/text/method/BaseKeyListener.java
+++ b/core/java/android/text/method/BaseKeyListener.java
@@ -310,7 +310,7 @@
             return len;
         }
 
-        offset = paint.getTextRunCursor(text, offset, len, Paint.DIRECTION_LTR /* not used */,
+        offset = paint.getTextRunCursor(text, offset, len, false /* LTR, not used */,
                 offset, Paint.CURSOR_AFTER);
 
         return adjustReplacementSpan(text, offset, false /* move to the end */);
diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java
index 5210447..be47320 100644
--- a/core/java/android/text/style/SuggestionSpan.java
+++ b/core/java/android/text/style/SuggestionSpan.java
@@ -420,7 +420,7 @@
             intent.putExtra(SuggestionSpan.SUGGESTION_SPAN_PICKED_HASHCODE, hashCode());
             context.sendBroadcast(intent);
         } else {
-            InputMethodManager imm = InputMethodManager.peekInstance();
+            InputMethodManager imm = context.getSystemService(InputMethodManager.class);
             if (imm != null) {
                 imm.notifySuggestionPicked(this, original, index);
             }
diff --git a/core/java/android/text/style/TextAppearanceSpan.java b/core/java/android/text/style/TextAppearanceSpan.java
index c17cfd5..2dc4f60 100644
--- a/core/java/android/text/style/TextAppearanceSpan.java
+++ b/core/java/android/text/style/TextAppearanceSpan.java
@@ -16,11 +16,13 @@
 
 package android.text.style;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
 import android.graphics.LeakyTypefaceStorage;
 import android.graphics.Typeface;
+import android.graphics.fonts.Font;
 import android.os.Parcel;
 import android.text.ParcelableSpan;
 import android.text.TextPaint;
@@ -38,6 +40,21 @@
     private final ColorStateList mTextColorLink;
     private final Typeface mTypeface;
 
+    private final int mTextFontWeight;
+
+    private final float mShadowRadius;
+    private final float mShadowDx;
+    private final float mShadowDy;
+    private final int mShadowColor;
+
+    private final boolean mHasElegantTextHeight;
+    private final boolean mElegantTextHeight;
+    private final boolean mHasLetterSpacing;
+    private final float mLetterSpacing;
+
+    private final String mFontFeatureSettings;
+    private final String mFontVariationSettings;
+
     /**
      * Uses the specified TextAppearance resource to determine the
      * text appearance.  The <code>appearance</code> should be, for example,
@@ -104,6 +121,34 @@
             }
         }
 
+        mTextFontWeight = a.getInt(com.android.internal.R.styleable
+                .TextAppearance_textFontWeight, -1);
+
+        mShadowRadius = a.getFloat(com.android.internal.R.styleable
+                .TextAppearance_shadowRadius, 0.0f);
+        mShadowDx = a.getFloat(com.android.internal.R.styleable
+                .TextAppearance_shadowDx, 0.0f);
+        mShadowDy = a.getFloat(com.android.internal.R.styleable
+                .TextAppearance_shadowDy, 0.0f);
+        mShadowColor = a.getInt(com.android.internal.R.styleable
+                .TextAppearance_shadowColor, 0);
+
+        mHasElegantTextHeight = a.hasValue(com.android.internal.R.styleable
+                .TextAppearance_elegantTextHeight);
+        mElegantTextHeight = a.getBoolean(com.android.internal.R.styleable
+                .TextAppearance_elegantTextHeight, false);
+
+        mHasLetterSpacing = a.hasValue(com.android.internal.R.styleable
+                .TextAppearance_letterSpacing);
+        mLetterSpacing = a.getFloat(com.android.internal.R.styleable
+                .TextAppearance_letterSpacing, 0.0f);
+
+        mFontFeatureSettings = a.getString(com.android.internal.R.styleable
+                .TextAppearance_fontFeatureSettings);
+
+        mFontVariationSettings = a.getString(com.android.internal.R.styleable
+                .TextAppearance_fontVariationSettings);
+
         a.recycle();
 
         if (colorList >= 0) {
@@ -129,6 +174,21 @@
         mTextColor = color;
         mTextColorLink = linkColor;
         mTypeface = null;
+
+        mTextFontWeight = -1;
+
+        mShadowRadius = 0.0f;
+        mShadowDx = 0.0f;
+        mShadowDy = 0.0f;
+        mShadowColor = 0;
+
+        mHasElegantTextHeight = false;
+        mElegantTextHeight = false;
+        mHasLetterSpacing = false;
+        mLetterSpacing = 0.0f;
+
+        mFontFeatureSettings = null;
+        mFontVariationSettings = null;
     }
 
     public TextAppearanceSpan(Parcel src) {
@@ -146,6 +206,21 @@
             mTextColorLink = null;
         }
         mTypeface = LeakyTypefaceStorage.readTypefaceFromParcel(src);
+
+        mTextFontWeight = src.readInt();
+
+        mShadowRadius = src.readFloat();
+        mShadowDx = src.readFloat();
+        mShadowDy = src.readFloat();
+        mShadowColor = src.readInt();
+
+        mHasElegantTextHeight = src.readBoolean();
+        mElegantTextHeight = src.readBoolean();
+        mHasLetterSpacing = src.readBoolean();
+        mLetterSpacing = src.readFloat();
+
+        mFontFeatureSettings = src.readString();
+        mFontVariationSettings = src.readString();
     }
 
     public int getSpanTypeId() {
@@ -183,6 +258,21 @@
             dest.writeInt(0);
         }
         LeakyTypefaceStorage.writeTypefaceToParcel(mTypeface, dest);
+
+        dest.writeInt(mTextFontWeight);
+
+        dest.writeFloat(mShadowRadius);
+        dest.writeFloat(mShadowDx);
+        dest.writeFloat(mShadowDy);
+        dest.writeInt(mShadowColor);
+
+        dest.writeBoolean(mHasElegantTextHeight);
+        dest.writeBoolean(mElegantTextHeight);
+        dest.writeBoolean(mHasLetterSpacing);
+        dest.writeFloat(mLetterSpacing);
+
+        dest.writeString(mFontFeatureSettings);
+        dest.writeString(mFontVariationSettings);
     }
 
     /**
@@ -225,6 +315,81 @@
         return mStyle;
     }
 
+    /**
+     * Returns the text font weight specified by this span, or <code>-1</code>
+     * if it does not specify one.
+     */
+    public int getTextFontWeight() {
+        return mTextFontWeight;
+    }
+
+    /**
+     * Returns the typeface specified by this span, or <code>null</code>
+     * if it does not specify one.
+     */
+    @Nullable
+    public Typeface getTypeface() {
+        return mTypeface;
+    }
+
+    /**
+     * Returns the color of the text shadow specified by this span, or <code>0</code>
+     * if it does not specify one.
+     */
+    public int getShadowColor() {
+        return mShadowColor;
+    }
+
+    /**
+     * Returns the horizontal offset of the text shadow specified by this span, or <code>0.0f</code>
+     * if it does not specify one.
+     */
+    public float getShadowDx() {
+        return mShadowDx;
+    }
+
+    /**
+     * Returns the vertical offset of the text shadow specified by this span, or <code>0.0f</code>
+     * if it does not specify one.
+     */
+    public float getShadowDy() {
+        return mShadowDy;
+    }
+
+    /**
+     * Returns the blur radius of the text shadow specified by this span, or <code>0.0f</code>
+     * if it does not specify one.
+     */
+    public float getShadowRadius() {
+        return mShadowRadius;
+    }
+
+    /**
+     * Returns the font feature settings specified by this span, or <code>null</code>
+     * if it does not specify one.
+     */
+    @Nullable
+    public String getFontFeatureSettings() {
+        return mFontFeatureSettings;
+    }
+
+    /**
+     * Returns the font variation settings specified by this span, or <code>null</code>
+     * if it does not specify one.
+     */
+    @Nullable
+    public String getFontVariationSettings() {
+        return mFontVariationSettings;
+    }
+
+    /**
+     * Returns the value of elegant height metrics flag specified by this span,
+     * or <code>false</code> if it does not specify one.
+     */
+    public boolean isElegantTextHeight() {
+        return mElegantTextHeight;
+    }
+
     @Override
     public void updateDrawState(TextPaint ds) {
         updateMeasureState(ds);
@@ -236,6 +401,10 @@
         if (mTextColorLink != null) {
             ds.linkColor = mTextColorLink.getColorForState(ds.drawableState, 0);
         }
+
+        if (mShadowColor != 0) {
+            ds.setShadowLayer(mShadowRadius, mShadowDx, mShadowDy, mShadowColor);
+        }
     }
 
     @Override
@@ -267,7 +436,16 @@
         }
 
         if (styledTypeface != null) {
-            int fake = style & ~styledTypeface.getStyle();
+            final Typeface readyTypeface;
+            if (mTextFontWeight >= 0) {
+                final int weight = Math.min(Font.FONT_WEIGHT_MAX, mTextFontWeight);
+                final boolean italic = (style & Typeface.ITALIC) != 0;
+                readyTypeface = ds.setTypeface(Typeface.create(styledTypeface, weight, italic));
+            } else {
+                readyTypeface = styledTypeface;
+            }
+
+            int fake = style & ~readyTypeface.getStyle();
 
             if ((fake & Typeface.BOLD) != 0) {
                 ds.setFakeBoldText(true);
@@ -277,11 +455,27 @@
                 ds.setTextSkewX(-0.25f);
             }
 
-            ds.setTypeface(styledTypeface);
+            ds.setTypeface(readyTypeface);
         }
 
         if (mTextSize > 0) {
             ds.setTextSize(mTextSize);
         }
+
+        if (mHasElegantTextHeight) {
+            ds.setElegantTextHeight(mElegantTextHeight);
+        }
+
+        if (mHasLetterSpacing) {
+            ds.setLetterSpacing(mLetterSpacing);
+        }
+
+        if (mFontFeatureSettings != null) {
+            ds.setFontFeatureSettings(mFontFeatureSettings);
+        }
+
+        if (mFontVariationSettings != null) {
+            ds.setFontVariationSettings(mFontVariationSettings);
+        }
     }
 }
diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java
index f8e8762..c4ef77a 100644
--- a/core/java/android/transition/TransitionManager.java
+++ b/core/java/android/transition/TransitionManager.java
@@ -189,6 +189,8 @@
         final ViewGroup sceneRoot = scene.getSceneRoot();
         if (!sPendingTransitions.contains(sceneRoot)) {
             if (transition == null) {
+                exitPreviousScene(sceneRoot);
+
                 scene.enter();
             } else {
                 sPendingTransitions.add(sceneRoot);
@@ -210,6 +212,14 @@
         }
     }
 
+    private static void exitPreviousScene(final ViewGroup sceneRoot) {
+        // Notify previous scene that it is being exited
+        final Scene previousScene = Scene.getCurrentScene(sceneRoot);
+        if (previousScene != null) {
+            previousScene.exit();
+        }
+    }
+
     @UnsupportedAppUsage
     private static ArrayMap<ViewGroup, ArrayList<Transition>> getRunningTransitions() {
         WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>> runningTransitions =
@@ -339,11 +349,7 @@
             transition.captureValues(sceneRoot, true);
         }
 
-        // Notify previous scene that it is being exited
-        Scene previousScene = Scene.getCurrentScene(sceneRoot);
-        if (previousScene != null) {
-            previousScene.exit();
-        }
+        exitPreviousScene(sceneRoot);
     }
 
     /**
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 0476cf8..183e833 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -35,6 +35,7 @@
     public static final String FFLAG_OVERRIDE_PREFIX = FFLAG_PREFIX + "override.";
     public static final String PERSIST_PREFIX = "persist." + FFLAG_OVERRIDE_PREFIX;
     public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid";
+    public static final String EMERGENCY_DIAL_SHORTCUTS = "settings_emergency_dial_shortcuts";
 
     private static final Map<String, String> DEFAULT_FLAGS;
     static {
@@ -45,7 +46,9 @@
         DEFAULT_FLAGS.put("settings_dynamic_homepage", "false");
         DEFAULT_FLAGS.put("settings_mobile_network_v2", "false");
         DEFAULT_FLAGS.put("settings_data_usage_v2", "false");
+        DEFAULT_FLAGS.put("settings_seamless_transfer", "false");
         DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "true");
+        DEFAULT_FLAGS.put(EMERGENCY_DIAL_SHORTCUTS, "false");
     }
 
     /**
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
index 533d725..1203541 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -410,11 +410,11 @@
                    NoSuchAlgorithmException {
         try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
             SignatureInfo signatureInfo = findSignature(apk);
-            return ApkSigningBlockUtils.generateApkVerity(apkPath, bufferFactory, signatureInfo);
+            return ApkVerityBuilder.generateApkVerity(apkPath, bufferFactory, signatureInfo);
         }
     }
 
-    static byte[] generateFsverityRootHash(String apkPath)
+    static byte[] generateApkVerityRootHash(String apkPath)
             throws IOException, SignatureNotFoundException, DigestException,
                    NoSuchAlgorithmException {
         try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
@@ -423,7 +423,7 @@
             if (vSigner.verityRootHash == null) {
                 return null;
             }
-            return ApkVerityBuilder.generateFsverityRootHash(
+            return ApkVerityBuilder.generateApkVerityRootHash(
                     apk, ByteBuffer.wrap(vSigner.verityRootHash), signatureInfo);
         }
     }
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
index 758cd2b..939522d 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
@@ -534,11 +534,11 @@
                    NoSuchAlgorithmException {
         try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
             SignatureInfo signatureInfo = findSignature(apk);
-            return ApkSigningBlockUtils.generateApkVerity(apkPath, bufferFactory, signatureInfo);
+            return ApkVerityBuilder.generateApkVerity(apkPath, bufferFactory, signatureInfo);
         }
     }
 
-    static byte[] generateFsverityRootHash(String apkPath)
+    static byte[] generateApkVerityRootHash(String apkPath)
             throws NoSuchAlgorithmException, DigestException, IOException,
                    SignatureNotFoundException {
         try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
@@ -547,7 +547,7 @@
             if (vSigner.verityRootHash == null) {
                 return null;
             }
-            return ApkVerityBuilder.generateFsverityRootHash(
+            return ApkVerityBuilder.generateApkVerityRootHash(
                     apk, ByteBuffer.wrap(vSigner.verityRootHash), signatureInfo);
         }
     }
diff --git a/core/java/android/util/apk/ApkSignatureVerifier.java b/core/java/android/util/apk/ApkSignatureVerifier.java
index de9f55b..a299b11 100644
--- a/core/java/android/util/apk/ApkSignatureVerifier.java
+++ b/core/java/android/util/apk/ApkSignatureVerifier.java
@@ -432,16 +432,16 @@
      *
      * @return FSverity root hash
      */
-    public static byte[] generateFsverityRootHash(String apkPath)
+    public static byte[] generateApkVerityRootHash(String apkPath)
             throws NoSuchAlgorithmException, DigestException, IOException {
         // first try v3
         try {
-            return ApkSignatureSchemeV3Verifier.generateFsverityRootHash(apkPath);
+            return ApkSignatureSchemeV3Verifier.generateApkVerityRootHash(apkPath);
         } catch (SignatureNotFoundException e) {
             // try older version
         }
         try {
-            return ApkSignatureSchemeV2Verifier.generateFsverityRootHash(apkPath);
+            return ApkSignatureSchemeV2Verifier.generateApkVerityRootHash(apkPath);
         } catch (SignatureNotFoundException e) {
             return null;
         }
diff --git a/core/java/android/util/apk/ApkSigningBlockUtils.java b/core/java/android/util/apk/ApkSigningBlockUtils.java
index e247c87..081033a 100644
--- a/core/java/android/util/apk/ApkSigningBlockUtils.java
+++ b/core/java/android/util/apk/ApkSigningBlockUtils.java
@@ -332,7 +332,7 @@
         try {
             byte[] expectedRootHash = parseVerityDigestAndVerifySourceLength(expectedDigest,
                     apk.length(), signatureInfo);
-            ApkVerityBuilder.ApkVerityResult verity = ApkVerityBuilder.generateApkVerity(apk,
+            ApkVerityBuilder.ApkVerityResult verity = ApkVerityBuilder.generateApkVerityTree(apk,
                     signatureInfo, new ByteBufferFactory() {
                         @Override
                         public ByteBuffer create(int capacity) {
@@ -348,26 +348,6 @@
     }
 
     /**
-     * Generates the fsverity header and hash tree to be used by kernel for the given apk. This
-     * method does not check whether the root hash exists in the Signing Block or not.
-     *
-     * <p>The output is stored in the {@link ByteBuffer} created by the given {@link
-     * ByteBufferFactory}.
-     *
-     * @return the root hash of the generated hash tree.
-     */
-    public static byte[] generateApkVerity(String apkPath, ByteBufferFactory bufferFactory,
-            SignatureInfo signatureInfo)
-            throws IOException, SignatureNotFoundException, SecurityException, DigestException,
-                   NoSuchAlgorithmException {
-        try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
-            ApkVerityBuilder.ApkVerityResult result = ApkVerityBuilder.generateApkVerity(apk,
-                    signatureInfo, bufferFactory);
-            return result.rootHash;
-        }
-    }
-
-    /**
      * Returns the ZIP End of Central Directory (EoCD) and its offset in the file.
      *
      * @throws IOException if an I/O error occurs while reading the file.
diff --git a/core/java/android/util/apk/ApkVerityBuilder.java b/core/java/android/util/apk/ApkVerityBuilder.java
index 2dd0117..edd09f8 100644
--- a/core/java/android/util/apk/ApkVerityBuilder.java
+++ b/core/java/android/util/apk/ApkVerityBuilder.java
@@ -16,6 +16,9 @@
 
 package android.util.apk;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
 import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.nio.ByteBuffer;
@@ -26,8 +29,10 @@
 import java.util.ArrayList;
 
 /**
- * ApkVerityBuilder builds the APK verity tree and the verity header, which will be used by the
- * kernel to verity the APK content on access.
+ * ApkVerityBuilder builds the APK verity tree and the verity header.  The generated tree format can
+ * be stored on disk for apk-verity setup and used by kernel.  Note that since the current
+ * implementation is different from the upstream, we call this implementation apk-verity instead of
+ * fs-verity.
  *
  * <p>Unlike a regular Merkle tree, APK verity tree does not cover the content fully. Due to
  * the existing APK format, it has to skip APK Signing Block and also has some special treatment for
@@ -35,7 +40,7 @@
  *
  * @hide
  */
-abstract class ApkVerityBuilder {
+public abstract class ApkVerityBuilder {
     private ApkVerityBuilder() {}
 
     private static final int CHUNK_SIZE_BYTES = 4096;  // Typical Linux block size
@@ -46,116 +51,137 @@
     private static final String JCA_DIGEST_ALGORITHM = "SHA-256";
     private static final byte[] DEFAULT_SALT = new byte[8];
 
-    static class ApkVerityResult {
-        public final ByteBuffer fsverityData;
+    /** Result generated by the builder. */
+    public static class ApkVerityResult {
+        /** Raw fs-verity metadata and Merkle tree ready to be deployed on disk. */
+        public final ByteBuffer verityData;
+
+        /** Size of the Merkle tree in {@code verityData}. */
+        public final int merkleTreeSize;
+
+        /** Root hash of the Merkle tree. */
         public final byte[] rootHash;
 
-        ApkVerityResult(ByteBuffer fsverityData, byte[] rootHash) {
-            this.fsverityData = fsverityData;
+        private ApkVerityResult(ByteBuffer verityData, int merkleTreeSize, byte[] rootHash) {
+            this.verityData = verityData;
+            this.merkleTreeSize = merkleTreeSize;
             this.rootHash = rootHash;
         }
     }
 
     /**
-     * Generates fsverity metadata and the Merkle tree into the {@link ByteBuffer} created by the
-     * {@link ByteBufferFactory}. The bytes layout in the buffer will be used by the kernel and is
-     * ready to be appended to the target file to set up fsverity. For fsverity to work, this data
-     * must be placed at the next page boundary, and the caller must add additional padding in that
-     * case.
+     * Generates the 4k, SHA-256 based Merkle tree for the given APK and stores in the {@link
+     * ByteBuffer} created by the {@link ByteBufferFactory}.  The output is suitable to be used as
+     * the on-disk format for fs-verity to use.
      *
-     * @return ApkVerityResult containing the fsverity data and the root hash of the Merkle tree.
+     * @return ApkVerityResult containing a buffer with the generated Merkle tree stored at the
+     *         front, the tree size, and the calculated root hash.
      */
-    static ApkVerityResult generateApkVerity(RandomAccessFile apk,
-            SignatureInfo signatureInfo, ByteBufferFactory bufferFactory)
+    @NonNull
+    public static ApkVerityResult generateFsVerityTree(@NonNull RandomAccessFile apk,
+            @NonNull ByteBufferFactory bufferFactory)
             throws IOException, SecurityException, NoSuchAlgorithmException, DigestException {
-        long signingBlockSize =
-                signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset;
-        long dataSize = apk.length() - signingBlockSize;
+        return generateVerityTree(apk, bufferFactory, null /* signatureInfo */,
+                false /* skipSigningBlock */);
+    }
+
+    /**
+     * Generates the 4k, SHA-256 based Merkle tree for the given APK and stores in the {@link
+     * ByteBuffer} created by the {@link ByteBufferFactory}.  The Merkle tree does not cover Signing
+     * Block specificed in {@code signatureInfo}.  The output is suitable to be used as the on-disk
+     * format for fs-verity to use (with elide and patch extensions).
+     *
+     * @return ApkVerityResult containing a buffer with the generated Merkle tree stored at the
+     *         front, the tree size, and the calculated root hash.
+     */
+    @NonNull
+    public static ApkVerityResult generateApkVerityTree(@NonNull RandomAccessFile apk,
+            @Nullable SignatureInfo signatureInfo, @NonNull ByteBufferFactory bufferFactory)
+            throws IOException, SecurityException, NoSuchAlgorithmException, DigestException {
+        return generateVerityTree(apk, bufferFactory, signatureInfo, true /* skipSigningBlock */);
+    }
+
+    @NonNull
+    private static ApkVerityResult generateVerityTree(@NonNull RandomAccessFile apk,
+            @NonNull ByteBufferFactory bufferFactory, @Nullable SignatureInfo signatureInfo,
+            boolean skipSigningBlock)
+            throws IOException, SecurityException, NoSuchAlgorithmException, DigestException {
+        long dataSize = apk.length();
+        if (skipSigningBlock) {
+            long signingBlockSize =
+                    signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset;
+            dataSize -= signingBlockSize;
+        }
         int[] levelOffset = calculateVerityLevelOffset(dataSize);
         int merkleTreeSize = levelOffset[levelOffset.length - 1];
 
         ByteBuffer output = bufferFactory.create(
                 merkleTreeSize
-                + CHUNK_SIZE_BYTES);  // maximum size of fsverity metadata
+                + CHUNK_SIZE_BYTES);  // maximum size of apk-verity metadata
         output.order(ByteOrder.LITTLE_ENDIAN);
-
         ByteBuffer tree = slice(output, 0, merkleTreeSize);
-        ByteBuffer header = slice(output, merkleTreeSize,
-                merkleTreeSize + FSVERITY_HEADER_SIZE_BYTES);
-        ByteBuffer extensions = slice(output, merkleTreeSize + FSVERITY_HEADER_SIZE_BYTES,
-                merkleTreeSize + CHUNK_SIZE_BYTES);
-        byte[] apkDigestBytes = new byte[DIGEST_SIZE_BYTES];
-        ByteBuffer apkDigest = ByteBuffer.wrap(apkDigestBytes);
-        apkDigest.order(ByteOrder.LITTLE_ENDIAN);
+        // Only use default salt in legacy case.
+        byte[] salt = skipSigningBlock ? DEFAULT_SALT : null;
+        byte[] apkRootHash = generateVerityTreeInternal(apk, signatureInfo, salt, levelOffset,
+                tree, skipSigningBlock);
+        return new ApkVerityResult(output, merkleTreeSize, apkRootHash);
+    }
 
-        // NB: Buffer limit is set inside once finished.
-        calculateFsveritySignatureInternal(apk, signatureInfo, tree, apkDigest, header, extensions);
-
-        // Put the reverse offset to fs-verity header at the end.
-        output.position(merkleTreeSize + FSVERITY_HEADER_SIZE_BYTES + extensions.limit());
-        output.putInt(FSVERITY_HEADER_SIZE_BYTES + extensions.limit()
-                + 4);  // size of this integer right before EOF
-        output.flip();
-
-        return new ApkVerityResult(output, apkDigestBytes);
+    static void generateApkVerityFooter(@NonNull RandomAccessFile apk,
+            @NonNull SignatureInfo signatureInfo, @NonNull ByteBuffer footerOutput)
+            throws IOException {
+        footerOutput.order(ByteOrder.LITTLE_ENDIAN);
+        generateApkVerityHeader(footerOutput, apk.length(), DEFAULT_SALT);
+        long signingBlockSize =
+                signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset;
+        generateApkVerityExtensions(footerOutput, signatureInfo.apkSigningBlockOffset,
+                signingBlockSize, signatureInfo.eocdOffset);
     }
 
     /**
-     * Calculates the fsverity root hash for integrity measurement.  This needs to be consistent to
-     * what kernel returns.
+     * Calculates the apk-verity root hash for integrity measurement.  This needs to be consistent
+     * to what kernel returns.
      */
-    static byte[] generateFsverityRootHash(RandomAccessFile apk, ByteBuffer apkDigest,
-            SignatureInfo signatureInfo)
+    @NonNull
+    static byte[] generateApkVerityRootHash(@NonNull RandomAccessFile apk,
+            @NonNull ByteBuffer apkDigest, @NonNull SignatureInfo signatureInfo)
             throws NoSuchAlgorithmException, DigestException, IOException {
-        ByteBuffer verityBlock = ByteBuffer.allocate(CHUNK_SIZE_BYTES)
-                .order(ByteOrder.LITTLE_ENDIAN);
-        ByteBuffer header = slice(verityBlock, 0, FSVERITY_HEADER_SIZE_BYTES);
-        ByteBuffer extensions = slice(verityBlock, FSVERITY_HEADER_SIZE_BYTES,
-                CHUNK_SIZE_BYTES - FSVERITY_HEADER_SIZE_BYTES);
+        assertSigningBlockAlignedAndHasFullPages(signatureInfo);
 
-        calculateFsveritySignatureInternal(apk, signatureInfo, null, null, header, extensions);
+        ByteBuffer footer = ByteBuffer.allocate(CHUNK_SIZE_BYTES).order(ByteOrder.LITTLE_ENDIAN);
+        generateApkVerityFooter(apk, signatureInfo, footer);
+        footer.flip();
 
         MessageDigest md = MessageDigest.getInstance(JCA_DIGEST_ALGORITHM);
-        md.update(header);
-        md.update(extensions);
+        md.update(footer);
         md.update(apkDigest);
         return md.digest();
     }
 
     /**
-     * Internal method to generate various parts of FSVerity constructs, including the header,
-     * extensions, Merkle tree, and the tree's root hash.  The output buffer is flipped to the
-     * generated data size and is readey for consuming.
+     * Generates the apk-verity header and hash tree to be used by kernel for the given apk. This
+     * method does not check whether the root hash exists in the Signing Block or not.
+     *
+     * <p>The output is stored in the {@link ByteBuffer} created by the given {@link
+     * ByteBufferFactory}.
+     *
+     * @return the root hash of the generated hash tree.
      */
-    private static void calculateFsveritySignatureInternal(
-            RandomAccessFile apk, SignatureInfo signatureInfo, ByteBuffer treeOutput,
-            ByteBuffer rootHashOutput, ByteBuffer headerOutput, ByteBuffer extensionsOutput)
-            throws IOException, NoSuchAlgorithmException, DigestException {
-        assertSigningBlockAlignedAndHasFullPages(signatureInfo);
-        long signingBlockSize =
-                signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset;
-        long dataSize = apk.length() - signingBlockSize;
-        int[] levelOffset = calculateVerityLevelOffset(dataSize);
-
-        if (treeOutput != null) {
-            byte[] apkRootHash = generateApkVerityTree(apk, signatureInfo, DEFAULT_SALT,
-                    levelOffset, treeOutput);
-            if (rootHashOutput != null) {
-                rootHashOutput.put(apkRootHash);
-                rootHashOutput.flip();
-            }
-        }
-
-        if (headerOutput != null) {
-            headerOutput.order(ByteOrder.LITTLE_ENDIAN);
-            generateFsverityHeader(headerOutput, apk.length(), levelOffset.length - 1,
-                    DEFAULT_SALT);
-        }
-
-        if (extensionsOutput != null) {
-            extensionsOutput.order(ByteOrder.LITTLE_ENDIAN);
-            generateFsverityExtensions(extensionsOutput, signatureInfo.apkSigningBlockOffset,
-                    signingBlockSize, signatureInfo.eocdOffset);
+    @NonNull
+    static byte[] generateApkVerity(@NonNull String apkPath,
+            @NonNull ByteBufferFactory bufferFactory, @NonNull SignatureInfo signatureInfo)
+            throws IOException, SignatureNotFoundException, SecurityException, DigestException,
+                   NoSuchAlgorithmException {
+        try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
+            ApkVerityResult result = generateVerityTree(apk, bufferFactory, signatureInfo,
+                    true /* skipSigningBlock */);
+            ByteBuffer footer = slice(result.verityData, result.merkleTreeSize,
+                    result.verityData.limit());
+            generateApkVerityFooter(apk, signatureInfo, footer);
+            // Put the reverse offset to apk-verity header at the end.
+            footer.putInt(footer.position() + 4);
+            result.verityData.limit(result.merkleTreeSize + footer.position());
+            return result.rootHash;
         }
     }
 
@@ -180,11 +206,14 @@
         private final byte[] mDigestBuffer = new byte[DIGEST_SIZE_BYTES];
         private final byte[] mSalt;
 
-        private BufferedDigester(byte[] salt, ByteBuffer output) throws NoSuchAlgorithmException {
+        private BufferedDigester(@Nullable byte[] salt, @NonNull ByteBuffer output)
+                throws NoSuchAlgorithmException {
             mSalt = salt;
             mOutput = output.slice();
             mMd = MessageDigest.getInstance(JCA_DIGEST_ALGORITHM);
-            mMd.update(mSalt);
+            if (mSalt != null) {
+                mMd.update(mSalt);
+            }
             mBytesDigestedSinceReset = 0;
         }
 
@@ -211,7 +240,9 @@
                     mMd.digest(mDigestBuffer, 0, mDigestBuffer.length);
                     mOutput.put(mDigestBuffer);
                     // After digest, MessageDigest resets automatically, so no need to reset again.
-                    mMd.update(mSalt);
+                    if (mSalt != null) {
+                        mMd.update(mSalt);
+                    }
                     mBytesDigestedSinceReset = 0;
                 }
             }
@@ -252,6 +283,26 @@
     // thus the syscall overhead is not too big.
     private static final int MMAP_REGION_SIZE_BYTES = 1024 * 1024;
 
+    private static void generateFsVerityDigestAtLeafLevel(RandomAccessFile file, ByteBuffer output)
+            throws IOException, NoSuchAlgorithmException, DigestException {
+        BufferedDigester digester = new BufferedDigester(null /* salt */, output);
+
+        // 1. Digest the whole file by chunks.
+        consumeByChunk(digester,
+                new MemoryMappedFileDataSource(file.getFD(), 0, file.length()),
+                MMAP_REGION_SIZE_BYTES);
+
+        // 2. Pad 0s up to the nearest 4096-byte block before hashing.
+        int lastIncompleteChunkSize = (int) (file.length() % CHUNK_SIZE_BYTES);
+        if (lastIncompleteChunkSize != 0) {
+            digester.consume(ByteBuffer.allocate(CHUNK_SIZE_BYTES - lastIncompleteChunkSize));
+        }
+        digester.assertEmptyBuffer();
+
+        // 3. Fill up the rest of buffer with 0s.
+        digester.fillUpLastOutputChunk();
+    }
+
     private static void generateApkVerityDigestAtLeafLevel(RandomAccessFile apk,
             SignatureInfo signatureInfo, byte[] salt, ByteBuffer output)
             throws IOException, NoSuchAlgorithmException, DigestException {
@@ -297,12 +348,20 @@
         digester.fillUpLastOutputChunk();
     }
 
-    private static byte[] generateApkVerityTree(RandomAccessFile apk, SignatureInfo signatureInfo,
-            byte[] salt, int[] levelOffset, ByteBuffer output)
+    @NonNull
+    private static byte[] generateVerityTreeInternal(@NonNull RandomAccessFile apk,
+            @Nullable SignatureInfo signatureInfo, @Nullable byte[] salt,
+            @NonNull int[] levelOffset, @NonNull ByteBuffer output, boolean skipSigningBlock)
             throws IOException, NoSuchAlgorithmException, DigestException {
         // 1. Digest the apk to generate the leaf level hashes.
-        generateApkVerityDigestAtLeafLevel(apk, signatureInfo, salt, slice(output,
-                    levelOffset[levelOffset.length - 2], levelOffset[levelOffset.length - 1]));
+        if (skipSigningBlock) {
+            assertSigningBlockAlignedAndHasFullPages(signatureInfo);
+            generateApkVerityDigestAtLeafLevel(apk, signatureInfo, salt, slice(output,
+                        levelOffset[levelOffset.length - 2], levelOffset[levelOffset.length - 1]));
+        } else {
+            generateFsVerityDigestAtLeafLevel(apk, slice(output,
+                        levelOffset[levelOffset.length - 2], levelOffset[levelOffset.length - 1]));
+        }
 
         // 2. Digest the lower level hashes bottom up.
         for (int level = levelOffset.length - 3; level >= 0; level--) {
@@ -324,7 +383,7 @@
         return rootHash;
     }
 
-    private static ByteBuffer generateFsverityHeader(ByteBuffer buffer, long fileSize, int depth,
+    private static ByteBuffer generateApkVerityHeader(ByteBuffer buffer, long fileSize,
             byte[] salt) {
         if (salt.length != 8) {
             throw new IllegalArgumentException("salt is not 8 bytes long");
@@ -351,13 +410,12 @@
         buffer.put(salt);                   // salt (8 bytes)
         skip(buffer, 22);                   // reserved
 
-        buffer.flip();
         return buffer;
     }
 
-    private static ByteBuffer generateFsverityExtensions(ByteBuffer buffer, long signingBlockOffset,
-            long signingBlockSize, long eocdOffset) {
-        // Snapshot of the FSVerity structs (subject to change once upstreamed).
+    private static ByteBuffer generateApkVerityExtensions(ByteBuffer buffer,
+            long signingBlockOffset, long signingBlockSize, long eocdOffset) {
+        // Snapshot of the experimental fs-verity structs (different from upstream).
         //
         // struct fsverity_extension_elide {
         //   __le64 offset;
@@ -409,7 +467,6 @@
             skip(buffer, kPadding);      // padding
         }
 
-        buffer.flip();
         return buffer;
     }
 
@@ -442,10 +499,11 @@
         return levelOffset;
     }
 
-    private static void assertSigningBlockAlignedAndHasFullPages(SignatureInfo signatureInfo) {
+    private static void assertSigningBlockAlignedAndHasFullPages(
+            @NonNull SignatureInfo signatureInfo) {
         if (signatureInfo.apkSigningBlockOffset % CHUNK_SIZE_BYTES != 0) {
             throw new IllegalArgumentException(
-                    "APK Signing Block does not start at the page  boundary: "
+                    "APK Signing Block does not start at the page boundary: "
                     + signatureInfo.apkSigningBlockOffset);
         }
 
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index ce16ffc..a872776 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -22,6 +22,7 @@
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.hardware.display.DisplayManagerGlobal;
+import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -153,7 +154,7 @@
         public String toString() { return "FRAME_CALLBACK_TOKEN"; }
     };
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final Object mLock = new Object();
 
     private final Looper mLooper;
diff --git a/core/java/android/view/DisplayListCanvas.java b/core/java/android/view/DisplayListCanvas.java
index 4b946d7..667fab5 100644
--- a/core/java/android/view/DisplayListCanvas.java
+++ b/core/java/android/view/DisplayListCanvas.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
+import android.graphics.BaseRecordingCanvas;
 import android.graphics.Bitmap;
 import android.graphics.CanvasProperty;
 import android.graphics.Paint;
@@ -35,7 +36,7 @@
  *
  * @hide
  */
-public final class DisplayListCanvas extends RecordingCanvas {
+public final class DisplayListCanvas extends BaseRecordingCanvas {
     // The recording canvas pool should be large enough to handle a deeply nested
     // view hierarchy because display lists are generated recursively.
     private static final int POOL_LIMIT = 25;
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index bfe1e95..3bab87a 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -17,8 +17,6 @@
 package android.view;
 
 import com.android.internal.os.IResultReceiver;
-import com.android.internal.view.IInputContext;
-import com.android.internal.view.IInputMethodClient;
 import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IShortcutService;
 
@@ -71,8 +69,7 @@
     boolean stopViewServer();            // Transaction #2
     boolean isViewServerRunning();       // Transaction #3
 
-    IWindowSession openSession(in IWindowSessionCallback callback, in IInputMethodClient client,
-            in IInputContext inputContext);
+    IWindowSession openSession(in IWindowSessionCallback callback);
 
     void getInitialDisplaySize(int displayId, out Point size);
     void getBaseDisplaySize(int displayId, out Point size);
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 8641d7f..c38fcf3 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -21,6 +21,7 @@
 import android.annotation.NonNull;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.method.MetaKeyKeyListener;
@@ -1256,7 +1257,7 @@
 
     @UnsupportedAppUsage
     private int mDeviceId;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private int mSource;
     private int mDisplayId;
     @UnsupportedAppUsage
@@ -1658,7 +1659,7 @@
      * @hide
      */
     @Override
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public final void recycle() {
         super.recycle();
         mCharacters = null;
diff --git a/core/java/android/view/NativeVectorDrawableAnimator.java b/core/java/android/view/NativeVectorDrawableAnimator.java
new file mode 100644
index 0000000..b0556a3
--- /dev/null
+++ b/core/java/android/view/NativeVectorDrawableAnimator.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+/**
+ * Exists just to allow for android.graphics & android.view package separation
+ *
+ * TODO: Get off of this coupling more cleanly somehow
+ *
+ * @hide
+ */
+public interface NativeVectorDrawableAnimator {
+    /** @hide */
+    long getAnimatorNativePtr();
+}
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index dc097a1..cf11fd0 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -31,6 +31,7 @@
 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Log;
@@ -146,7 +147,7 @@
     private static final SparseArray<PointerIcon> gSystemIcons = new SparseArray<PointerIcon>();
     private static boolean sUseLargeIcons = false;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final int mType;
     private int mSystemIconResourceId;
     @UnsupportedAppUsage
@@ -319,7 +320,7 @@
      * @throws IllegalArgumentException if context is null.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public PointerIcon load(@NonNull Context context) {
         if (context == null) {
             throw new IllegalArgumentException("context must not be null");
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index fcea0c3..8ae9127 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -24,7 +24,6 @@
 import android.graphics.Outline;
 import android.graphics.Paint;
 import android.graphics.Rect;
-import android.graphics.drawable.AnimatedVectorDrawable;
 
 import dalvik.annotation.optimization.CriticalNative;
 import dalvik.annotation.optimization.FastNative;
@@ -148,12 +147,12 @@
      * @hide
      */
     final long mNativeRenderNode;
-    private final View mOwningView;
+    private final AnimationHost mAnimationHost;
 
-    private RenderNode(String name, View owningView) {
+    private RenderNode(String name, AnimationHost animationHost) {
         mNativeRenderNode = nCreate(name);
         NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativeRenderNode);
-        mOwningView = owningView;
+        mAnimationHost = animationHost;
     }
 
     /**
@@ -162,7 +161,7 @@
     private RenderNode(long nativePtr) {
         mNativeRenderNode = nativePtr;
         NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativeRenderNode);
-        mOwningView = null;
+        mAnimationHost = null;
     }
 
     /**
@@ -174,8 +173,8 @@
      * @return A new RenderNode.
      */
     @UnsupportedAppUsage
-    public static RenderNode create(String name, @Nullable View owningView) {
-        return new RenderNode(name, owningView);
+    public static RenderNode create(String name, @Nullable AnimationHost animationHost) {
+        return new RenderNode(name, animationHost);
     }
 
     /**
@@ -189,10 +188,37 @@
     }
 
     /**
+     * Listens for RenderNode position updates for synchronous window movement.
+     *
+     * This is not suitable for generic position listening, it is only designed & intended
+     * for use by things which require external position events like SurfaceView, PopupWindow, etc..
+     *
+     * @hide
+     */
+    interface PositionUpdateListener {
+
+        /**
+         * Called by native by a Rendering Worker thread to update window position
+         *
+         * @hide
+         */
+        void positionChanged(long frameNumber, int left, int top, int right, int bottom);
+
+        /**
+         * Called by native on RenderThread to notify that the view is no longer in the
+         * draw tree. UI thread is blocked at this point.
+         *
+         * @hide
+         */
+        void positionLost(long frameNumber);
+
+    }
+
+    /**
      * Enable callbacks for position changes.
      */
-    public void requestPositionUpdates(SurfaceView view) {
-        nRequestPositionUpdates(mNativeRenderNode, view);
+    public void requestPositionUpdates(PositionUpdateListener listener) {
+        nRequestPositionUpdates(mNativeRenderNode, listener);
     }
 
 
@@ -843,30 +869,72 @@
         return nGetDebugSize(mNativeRenderNode);
     }
 
+    /**
+     * Sets whether or not to allow force dark to apply to this RenderNode.
+     *
+     * Setting this to false will disable the auto-dark feature on everything this RenderNode
+     * draws, including any descendants.
+     *
+     * Setting this to true will allow this RenderNode to be automatically made dark, however
+     * a value of 'true' will not override any 'false' value in its parent chain nor will
+     * it prevent any 'false' in any of its children.
+     *
+     * @param allow Whether or not to allow force dark.
+     * @return true If the value has changed, false otherwise.
+     */
+    public boolean setAllowForceDark(boolean allow) {
+        return nSetAllowForceDark(mNativeRenderNode, allow);
+    }
+
+    /**
+     * See {@link #setAllowForceDark(boolean)}
+     *
+     * @return true if force dark is allowed (default), false if it is disabled
+     */
+    public boolean getAllowForceDark() {
+        return nGetAllowForceDark(mNativeRenderNode);
+    }
+
     ///////////////////////////////////////////////////////////////////////////
     // Animations
     ///////////////////////////////////////////////////////////////////////////
 
+    /**
+     * TODO: Figure out if this can be eliminated/refactored away
+     *
+     * For now this interface exists to de-couple RenderNode from anything View-specific in a
+     * bit of a kludge.
+     *
+     * @hide */
+    interface AnimationHost {
+        void registerAnimatingRenderNode(RenderNode animator);
+        void registerVectorDrawableAnimator(NativeVectorDrawableAnimator animator);
+        boolean isAttached();
+    }
+
+    /** @hide */
     public void addAnimator(RenderNodeAnimator animator) {
-        if (mOwningView == null || mOwningView.mAttachInfo == null) {
+        if (!isAttached()) {
             throw new IllegalStateException("Cannot start this animator on a detached view!");
         }
         nAddAnimator(mNativeRenderNode, animator.getNativeAnimator());
-        mOwningView.mAttachInfo.mViewRootImpl.registerAnimatingRenderNode(this);
+        mAnimationHost.registerAnimatingRenderNode(this);
     }
 
+    /** @hide */
     public boolean isAttached() {
-        return mOwningView != null && mOwningView.mAttachInfo != null;
+        return mAnimationHost != null && mAnimationHost.isAttached();
     }
 
-    public void registerVectorDrawableAnimator(
-            AnimatedVectorDrawable.VectorDrawableAnimatorRT animatorSet) {
-        if (mOwningView == null || mOwningView.mAttachInfo == null) {
+    /** @hide */
+    public void registerVectorDrawableAnimator(NativeVectorDrawableAnimator animatorSet) {
+        if (!isAttached()) {
             throw new IllegalStateException("Cannot start this animator on a detached view!");
         }
-        mOwningView.mAttachInfo.mViewRootImpl.registerVectorDrawableAnimator(animatorSet);
+        mAnimationHost.registerVectorDrawableAnimator(animatorSet);
     }
 
+    /** @hide */
     public void endAllAnimators() {
         nEndAllAnimators(mNativeRenderNode);
     }
@@ -880,7 +948,8 @@
     private static native long nGetNativeFinalizer();
     private static native void nOutput(long renderNode);
     private static native int nGetDebugSize(long renderNode);
-    private static native void nRequestPositionUpdates(long renderNode, SurfaceView callback);
+    private static native void nRequestPositionUpdates(long renderNode,
+            PositionUpdateListener callback);
 
     // Animations
 
@@ -1043,4 +1112,8 @@
     private static native int nGetWidth(long renderNode);
     @CriticalNative
     private static native int nGetHeight(long renderNode);
+    @CriticalNative
+    private static native boolean nSetAllowForceDark(long renderNode, boolean allowForceDark);
+    @CriticalNative
+    private static native boolean nGetAllowForceDark(long renderNode);
 }
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 427f570..6fb1bba 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -895,6 +895,7 @@
         HwuiContext(boolean isWideColorGamut) {
             mRenderNode = RenderNode.create("HwuiCanvas", null);
             mRenderNode.setClipToBounds(false);
+            mRenderNode.setAllowForceDark(false);
             mIsWideColorGamut = isWideColorGamut;
             mHwuiRenderer = nHwuiCreate(mRenderNode.mNativeRenderNode, mNativeObject,
                     isWideColorGamut);
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 79eafa8..7271a9e 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -70,15 +70,8 @@
     private static native void nativeDestroy(long nativeObject);
     private static native void nativeDisconnect(long nativeObject);
 
-    private static native Bitmap nativeScreenshot(IBinder displayToken,
-            Rect sourceCrop, int width, int height, int minLayer, int maxLayer,
-            boolean allLayers, boolean useIdentityTransform, int rotation);
-    private static native GraphicBuffer nativeScreenshotToBuffer(IBinder displayToken,
-            Rect sourceCrop, int width, int height, int minLayer, int maxLayer,
-            boolean allLayers, boolean useIdentityTransform, int rotation);
-    private static native void nativeScreenshot(IBinder displayToken, Surface consumer,
-            Rect sourceCrop, int width, int height, int minLayer, int maxLayer,
-            boolean allLayers, boolean useIdentityTransform);
+    private static native GraphicBuffer nativeScreenshot(IBinder displayToken,
+            Rect sourceCrop, int width, int height, boolean useIdentityTransform, int rotation);
     private static native GraphicBuffer nativeCaptureLayers(IBinder layerHandleToken,
             Rect sourceCrop, float frameScale);
 
@@ -1189,52 +1182,39 @@
     }
 
     /**
-     * Copy the current screen contents into the provided {@link Surface}
-     *
-     * @param display The display to take the screenshot of.
-     * @param consumer The {@link Surface} to take the screenshot into.
-     * @param width The desired width of the returned bitmap; the raw
-     * screen will be scaled down to this size.
-     * @param height The desired height of the returned bitmap; the raw
-     * screen will be scaled down to this size.
-     * @param minLayer The lowest (bottom-most Z order) surface layer to
-     * include in the screenshot.
-     * @param maxLayer The highest (top-most Z order) surface layer to
-     * include in the screenshot.
-     * @param useIdentityTransform Replace whatever transformation (rotation,
-     * scaling, translation) the surface layers are currently using with the
-     * identity transformation while taking the screenshot.
-     */
-    public static void screenshot(IBinder display, Surface consumer,
-            int width, int height, int minLayer, int maxLayer,
-            boolean useIdentityTransform) {
-        screenshot(display, consumer, new Rect(), width, height, minLayer, maxLayer,
-                false, useIdentityTransform);
-    }
-
-    /**
-     * Copy the current screen contents into the provided {@link Surface}
-     *
-     * @param display The display to take the screenshot of.
-     * @param consumer The {@link Surface} to take the screenshot into.
-     * @param width The desired width of the returned bitmap; the raw
-     * screen will be scaled down to this size.
-     * @param height The desired height of the returned bitmap; the raw
-     * screen will be scaled down to this size.
-     */
-    public static void screenshot(IBinder display, Surface consumer,
-            int width, int height) {
-        screenshot(display, consumer, new Rect(), width, height, 0, 0, true, false);
-    }
-
-    /**
-     * Copy the current screen contents into the provided {@link Surface}
-     *
-     * @param display The display to take the screenshot of.
-     * @param consumer The {@link Surface} to take the screenshot into.
+     * @see SurfaceControl#screenshot(IBinder, Surface, Rect, int, int, boolean, int)
      */
     public static void screenshot(IBinder display, Surface consumer) {
-        screenshot(display, consumer, new Rect(), 0, 0, 0, 0, true, false);
+        screenshot(display, consumer, new Rect(), 0, 0, false, 0);
+    }
+
+    /**
+     * Copy the current screen contents into the provided {@link Surface}
+     *
+     * @param consumer The {@link Surface} to take the screenshot into.
+     * @see SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)
+     */
+    public static void screenshot(IBinder display, Surface consumer, Rect sourceCrop, int width,
+            int height, boolean useIdentityTransform, int rotation) {
+        if (consumer == null) {
+            throw new IllegalArgumentException("consumer must not be null");
+        }
+
+        final GraphicBuffer buffer = screenshotToBuffer(display, sourceCrop, width, height,
+                useIdentityTransform, rotation);
+        try {
+            consumer.attachAndQueueBuffer(buffer);
+        } catch (RuntimeException e) {
+            Log.w(TAG, "Failed to take screenshot - " + e.getMessage());
+        }
+    }
+
+    /**
+     * @see SurfaceControl#screenshot(Rect, int, int, boolean, int)}
+     */
+    @UnsupportedAppUsage
+    public static Bitmap screenshot(Rect sourceCrop, int width, int height, int rotation) {
+        return screenshot(sourceCrop, width, height, false, rotation);
     }
 
     /**
@@ -1242,79 +1222,16 @@
      * Note: If you want to modify the Bitmap in software, you will need to copy the Bitmap into
      * a software Bitmap using {@link Bitmap#copy(Bitmap.Config, boolean)}
      *
-     * CAVEAT: Versions of screenshot that return a {@link Bitmap} can
-     * be extremely slow; avoid use unless absolutely necessary; prefer
-     * the versions that use a {@link Surface} instead, such as
-     * {@link SurfaceControl#screenshot(IBinder, Surface)}.
+     * CAVEAT: Versions of screenshot that return a {@link Bitmap} can be extremely slow; avoid use
+     * unless absolutely necessary; prefer the versions that use a {@link Surface} such as
+     * {@link SurfaceControl#screenshot(IBinder, Surface)} or {@link GraphicBuffer} such as
+     * {@link SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)}.
      *
-     * @param sourceCrop The portion of the screen to capture into the Bitmap;
-     * caller may pass in 'new Rect()' if no cropping is desired.
-     * @param width The desired width of the returned bitmap; the raw
-     * screen will be scaled down to this size.
-     * @param height The desired height of the returned bitmap; the raw
-     * screen will be scaled down to this size.
-     * @param minLayer The lowest (bottom-most Z order) surface layer to
-     * include in the screenshot.
-     * @param maxLayer The highest (top-most Z order) surface layer to
-     * include in the screenshot.
-     * @param useIdentityTransform Replace whatever transformation (rotation,
-     * scaling, translation) the surface layers are currently using with the
-     * identity transformation while taking the screenshot.
-     * @param rotation Apply a custom clockwise rotation to the screenshot, i.e.
-     * Surface.ROTATION_0,90,180,270. Surfaceflinger will always take
-     * screenshots in its native portrait orientation by default, so this is
-     * useful for returning screenshots that are independent of device
-     * orientation.
-     * @return Returns a hardware Bitmap containing the screen contents, or null
-     * if an error occurs. Make sure to call Bitmap.recycle() as soon as
-     * possible, once its content is not needed anymore.
+     * @see SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)}
      */
     @UnsupportedAppUsage
     public static Bitmap screenshot(Rect sourceCrop, int width, int height,
-            int minLayer, int maxLayer, boolean useIdentityTransform,
-            int rotation) {
-        // TODO: should take the display as a parameter
-        IBinder displayToken = SurfaceControl.getBuiltInDisplay(
-                SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN);
-        return nativeScreenshot(displayToken, sourceCrop, width, height,
-                minLayer, maxLayer, false, useIdentityTransform, rotation);
-    }
-
-    /**
-     * Like {@link SurfaceControl#screenshot(Rect, int, int, int, int, boolean, int)}
-     * but returns a GraphicBuffer.
-     */
-    public static GraphicBuffer screenshotToBuffer(Rect sourceCrop, int width, int height,
-            int minLayer, int maxLayer, boolean useIdentityTransform,
-            int rotation) {
-        IBinder displayToken = SurfaceControl.getBuiltInDisplay(
-                SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN);
-        return nativeScreenshotToBuffer(displayToken, sourceCrop, width, height,
-                minLayer, maxLayer, false, useIdentityTransform, rotation);
-    }
-
-    /**
-     * Like {@link SurfaceControl#screenshot(Rect, int, int, int, int, boolean, int)} but
-     * includes all Surfaces in the screenshot. This will also update the orientation so it
-     * sends the correct coordinates to SF based on the rotation value.
-     *
-     * @param sourceCrop The portion of the screen to capture into the Bitmap;
-     * caller may pass in 'new Rect()' if no cropping is desired.
-     * @param width The desired width of the returned bitmap; the raw
-     * screen will be scaled down to this size.
-     * @param height The desired height of the returned bitmap; the raw
-     * screen will be scaled down to this size.
-     * @param rotation Apply a custom clockwise rotation to the screenshot, i.e.
-     * Surface.ROTATION_0,90,180,270. Surfaceflinger will always take
-     * screenshots in its native portrait orientation by default, so this is
-     * useful for returning screenshots that are independent of device
-     * orientation.
-     * @return Returns a Bitmap containing the screen contents, or null
-     * if an error occurs. Make sure to call Bitmap.recycle() as soon as
-     * possible, once its content is not needed anymore.
-     */
-    @UnsupportedAppUsage
-    public static Bitmap screenshot(Rect sourceCrop, int width, int height, int rotation) {
+            boolean useIdentityTransform, int rotation) {
         // TODO: should take the display as a parameter
         IBinder displayToken = SurfaceControl.getBuiltInDisplay(
                 SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN);
@@ -1323,22 +1240,45 @@
         }
 
         SurfaceControl.rotateCropForSF(sourceCrop, rotation);
-        return nativeScreenshot(displayToken, sourceCrop, width, height, 0, 0, true,
-                false, rotation);
+        final GraphicBuffer buffer = screenshotToBuffer(displayToken, sourceCrop, width, height,
+                useIdentityTransform, rotation);
+
+        if (buffer == null) {
+            Log.w(TAG, "Failed to take screenshot");
+            return null;
+        }
+        return Bitmap.createHardwareBitmap(buffer);
     }
 
-    @UnsupportedAppUsage
-    private static void screenshot(IBinder display, Surface consumer, Rect sourceCrop,
-            int width, int height, int minLayer, int maxLayer, boolean allLayers,
-            boolean useIdentityTransform) {
+    /**
+     * Captures all the surfaces in a display and returns a {@link GraphicBuffer} with the content.
+     *
+     * @param display              The display to take the screenshot of.
+     * @param sourceCrop           The portion of the screen to capture into the Bitmap; caller may
+     *                             pass in 'new Rect()' if no cropping is desired.
+     * @param width                The desired width of the returned bitmap; the raw screen will be
+     *                             scaled down to this size; caller may pass in 0 if no scaling is
+     *                             desired.
+     * @param height               The desired height of the returned bitmap; the raw screen will
+     *                             be scaled down to this size; caller may pass in 0 if no scaling
+     *                             is desired.
+     * @param useIdentityTransform Replace whatever transformation (rotation, scaling, translation)
+     *                             the surface layers are currently using with the identity
+     *                             transformation while taking the screenshot.
+     * @param rotation             Apply a custom clockwise rotation to the screenshot, i.e.
+     *                             Surface.ROTATION_0,90,180,270. SurfaceFlinger will always take
+     *                             screenshots in its native portrait orientation by default, so
+     *                             this is useful for returning screenshots that are independent of
+     *                             device orientation.
+     * @return Returns a GraphicBuffer that contains the captured content.
+     */
+    public static GraphicBuffer screenshotToBuffer(IBinder display, Rect sourceCrop, int width,
+            int height, boolean useIdentityTransform, int rotation) {
         if (display == null) {
             throw new IllegalArgumentException("displayToken must not be null");
         }
-        if (consumer == null) {
-            throw new IllegalArgumentException("consumer must not be null");
-        }
-        nativeScreenshot(display, consumer, sourceCrop, width, height,
-                minLayer, maxLayer, allLayers, useIdentityTransform);
+
+        return nativeScreenshot(display, sourceCrop, width, height, useIdentityTransform, rotation);
     }
 
     private static void rotateCropForSF(Rect crop, int rot) {
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 514a11e..e71182c 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -209,7 +209,7 @@
 
     public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        mRenderNode.requestPositionUpdates(this);
+        mRenderNode.requestPositionUpdates(mPositionListener);
 
         setWillNotDraw(true);
     }
@@ -826,81 +826,80 @@
 
     private Rect mRTLastReportedPosition = new Rect();
 
-    /**
-     * Called by native by a Rendering Worker thread to update the window position
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public final void updateSurfacePosition_renderWorker(long frameNumber,
-            int left, int top, int right, int bottom) {
-        if (mSurfaceControl == null) {
-            return;
-        }
+    private RenderNode.PositionUpdateListener mPositionListener =
+            new RenderNode.PositionUpdateListener() {
 
-        // TODO: This is teensy bit racey in that a brand new SurfaceView moving on
-        // its 2nd frame if RenderThread is running slowly could potentially see
-        // this as false, enter the branch, get pre-empted, then this comes along
-        // and reports a new position, then the UI thread resumes and reports
-        // its position. This could therefore be de-sync'd in that interval, but
-        // the synchronization would violate the rule that RT must never block
-        // on the UI thread which would open up potential deadlocks. The risk of
-        // a single-frame desync is therefore preferable for now.
-        mRtHandlingPositionUpdates = true;
-        if (mRTLastReportedPosition.left == left
-                && mRTLastReportedPosition.top == top
-                && mRTLastReportedPosition.right == right
-                && mRTLastReportedPosition.bottom == bottom) {
-            return;
-        }
-        try {
-            if (DEBUG) {
-                Log.d(TAG, String.format("%d updateSurfacePosition RenderWorker, frameNr = %d, " +
-                        "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
-                        frameNumber, left, top, right, bottom));
+        @Override
+        public void positionChanged(long frameNumber, int left, int top, int right, int bottom) {
+            if (mSurfaceControl == null) {
+                return;
             }
-            mRTLastReportedPosition.set(left, top, right, bottom);
-            setParentSpaceRectangle(mRTLastReportedPosition, frameNumber);
-            // Now overwrite mRTLastReportedPosition with our values
-        } catch (Exception ex) {
-            Log.e(TAG, "Exception from repositionChild", ex);
-        }
-    }
 
-    /**
-     * Called by native on RenderThread to notify that the view is no longer in the
-     * draw tree. UI thread is blocked at this point.
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public final void surfacePositionLost_uiRtSync(long frameNumber) {
-        if (DEBUG) {
-            Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
-                    System.identityHashCode(this), frameNumber));
+            // TODO: This is teensy bit racey in that a brand new SurfaceView moving on
+            // its 2nd frame if RenderThread is running slowly could potentially see
+            // this as false, enter the branch, get pre-empted, then this comes along
+            // and reports a new position, then the UI thread resumes and reports
+            // its position. This could therefore be de-sync'd in that interval, but
+            // the synchronization would violate the rule that RT must never block
+            // on the UI thread which would open up potential deadlocks. The risk of
+            // a single-frame desync is therefore preferable for now.
+            mRtHandlingPositionUpdates = true;
+            if (mRTLastReportedPosition.left == left
+                    && mRTLastReportedPosition.top == top
+                    && mRTLastReportedPosition.right == right
+                    && mRTLastReportedPosition.bottom == bottom) {
+                return;
+            }
+            try {
+                if (DEBUG) {
+                    Log.d(TAG, String.format(
+                            "%d updateSurfacePosition RenderWorker, frameNr = %d, "
+                                    + "postion = [%d, %d, %d, %d]",
+                            System.identityHashCode(this), frameNumber,
+                            left, top, right, bottom));
+                }
+                mRTLastReportedPosition.set(left, top, right, bottom);
+                setParentSpaceRectangle(mRTLastReportedPosition, frameNumber);
+                // Now overwrite mRTLastReportedPosition with our values
+            } catch (Exception ex) {
+                Log.e(TAG, "Exception from repositionChild", ex);
+            }
         }
-        mRTLastReportedPosition.setEmpty();
 
-        if (mSurfaceControl == null) {
-            return;
-        }
-        if (mRtHandlingPositionUpdates) {
-            mRtHandlingPositionUpdates = false;
-            // This callback will happen while the UI thread is blocked, so we can
-            // safely access other member variables at this time.
-            // So do what the UI thread would have done if RT wasn't handling position
-            // updates.
-            if (!mScreenRect.isEmpty() && !mScreenRect.equals(mRTLastReportedPosition)) {
-                try {
-                    if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition, " +
-                            "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
-                            mScreenRect.left, mScreenRect.top,
-                            mScreenRect.right, mScreenRect.bottom));
-                    setParentSpaceRectangle(mScreenRect, frameNumber);
-                } catch (Exception ex) {
-                    Log.e(TAG, "Exception configuring surface", ex);
+        @Override
+        public void positionLost(long frameNumber) {
+            if (DEBUG) {
+                Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
+                        System.identityHashCode(this), frameNumber));
+            }
+            mRTLastReportedPosition.setEmpty();
+
+            if (mSurfaceControl == null) {
+                return;
+            }
+            if (mRtHandlingPositionUpdates) {
+                mRtHandlingPositionUpdates = false;
+                // This callback will happen while the UI thread is blocked, so we can
+                // safely access other member variables at this time.
+                // So do what the UI thread would have done if RT wasn't handling position
+                // updates.
+                if (!mScreenRect.isEmpty() && !mScreenRect.equals(mRTLastReportedPosition)) {
+                    try {
+                        if (DEBUG) {
+                            Log.d(TAG, String.format("%d updateSurfacePosition, "
+                                            + "postion = [%d, %d, %d, %d]",
+                                    System.identityHashCode(this),
+                                    mScreenRect.left, mScreenRect.top,
+                                    mScreenRect.right, mScreenRect.bottom));
+                        }
+                        setParentSpaceRectangle(mScreenRect, frameNumber);
+                    } catch (Exception ex) {
+                        Log.e(TAG, "Exception configuring surface", ex);
+                    }
                 }
             }
         }
-    }
+    };
 
     private SurfaceHolder.Callback[] getSurfaceCallbacks() {
         SurfaceHolder.Callback callbacks[];
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 6737839..42690ce 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -25,7 +25,6 @@
 import android.graphics.Bitmap;
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.graphics.drawable.AnimatedVectorDrawable;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
@@ -914,8 +913,7 @@
         nRegisterAnimatingRenderNode(mRootNode.mNativeRenderNode, animator.mNativeRenderNode);
     }
 
-    void registerVectorDrawableAnimator(
-        AnimatedVectorDrawable.VectorDrawableAnimatorRT animator) {
+    void registerVectorDrawableAnimator(NativeVectorDrawableAnimator animator) {
         nRegisterVectorDrawableAnimator(mRootNode.mNativeRenderNode,
                 animator.getAnimatorNativePtr());
     }
@@ -976,6 +974,25 @@
         }
     }
 
+    /** The root of everything */
+    public @NonNull RenderNode getRootNode() {
+        return mRootNode;
+    }
+
+    private boolean mForceDark = false;
+
+    /**
+     * Whether or not the force-dark feature should be used for this renderer.
+     */
+    public boolean setForceDark(boolean enable) {
+        if (mForceDark != enable) {
+            mForceDark = enable;
+            nSetForceDark(mNativeProxy, enable);
+            return true;
+        }
+        return false;
+    }
+
     /**
      * Basic synchronous renderer. Currently only used to render the Magnifier, so use with care.
      * TODO: deduplicate against ThreadedRenderer.
@@ -1255,4 +1272,5 @@
     private static native void nSetIsolatedProcess(boolean enabled);
     private static native void nSetContextPriority(int priority);
     private static native void nAllocateBuffers(long nativeProxy, Surface window);
+    private static native void nSetForceDark(long nativeProxy, boolean enabled);
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 9bc53ed..78e6dd8 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4582,7 +4582,7 @@
     /**
      * Object that handles automatic animation of view properties.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private ViewPropertyAnimator mAnimator = null;
 
     /**
@@ -4864,7 +4864,7 @@
         setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS);
         mUserPaddingStart = UNDEFINED_PADDING;
         mUserPaddingEnd = UNDEFINED_PADDING;
-        mRenderNode = RenderNode.create(getClass().getName(), this);
+        mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this));
 
         if (!sCompatibilityDone && context != null) {
             final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion;
@@ -5732,7 +5732,7 @@
     @UnsupportedAppUsage
     View() {
         mResources = null;
-        mRenderNode = RenderNode.create(getClass().getName(), this);
+        mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this));
     }
 
     final boolean debugDraw() {
@@ -6876,7 +6876,7 @@
      * @param requestCode The request code to use.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public void startActivityForResult(Intent intent, int requestCode) {
         mStartActivityRequestWho = "@android:view:" + System.identityHashCode(this);
         getContext().startActivityForResult(mStartActivityRequestWho, intent, requestCode, null);
@@ -7315,7 +7315,7 @@
         // Here we check whether we still need the default focus highlight, and switch it on/off.
         switchDefaultFocusHighlight();
 
-        InputMethodManager imm = InputMethodManager.peekInstance();
+        InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
         if (!gainFocus) {
             if (isPressed()) {
                 setPressed(false);
@@ -8523,6 +8523,11 @@
         }
         if (importance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS
                 || importance == IMPORTANT_FOR_AUTOFILL_NO) {
+            if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) {
+                Log.v(AUTOFILL_LOG_TAG, "View (autofillId=" +  getAutofillViewId() + ", "
+                        + getClass() + ") is not important for autofill because its "
+                        + "importance is " + importance);
+            }
             return false;
         }
 
@@ -12476,7 +12481,7 @@
         mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH;
         onFinishTemporaryDetach();
         if (hasWindowFocus() && hasFocus()) {
-            InputMethodManager.getInstance().focusIn(this);
+            getContext().getSystemService(InputMethodManager.class).focusIn(this);
         }
         notifyEnterOrExitForAutoFillIfNeeded(true);
     }
@@ -12867,7 +12872,7 @@
      *        focus, false otherwise.
      */
     public void onWindowFocusChanged(boolean hasWindowFocus) {
-        InputMethodManager imm = InputMethodManager.peekInstance();
+        InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
         if (!hasWindowFocus) {
             if (isPressed()) {
                 setPressed(false);
@@ -15241,6 +15246,44 @@
     }
 
     /**
+     * Sets whether or not to allow force dark to apply to this view.
+     *
+     * Setting this to false will disable the auto-dark feature on everything this view
+     * draws, including any descendants.
+     *
+     * Setting this to true will allow this view to be automatically made dark, however
+     * a value of 'true' will not override any 'false' value in its parent chain nor will
+     * it prevent any 'false' in any of its children.
+     *
+     * The default behavior of force dark is also influenced by the Theme's
+     * {@link android.R.styleable#Theme_isLightTheme isLightTheme} attribute.
+     * If a theme is isLightTheme="false", then force dark is globally disabled for that theme.
+     *
+     * @param allow Whether or not to allow force dark.
+     *
+     * @hide
+     */
+    public void setAllowForceDark(boolean allow) {
+        if (mRenderNode.setAllowForceDark(allow)) {
+            // Currently toggling force-dark requires a new display list push to apply
+            // TODO: Make it not clobber the display list so this is just a damageSelf() instead
+            invalidate();
+        }
+    }
+
+    /**
+     * See {@link #setAllowForceDark(boolean)}
+     *
+     * @return true if force dark is allowed (default), false if it is disabled
+     *
+     * @hide
+     */
+    @ViewDebug.ExportedProperty(category = "drawing")
+    public boolean getAllowForceDark() {
+        return mRenderNode.getAllowForceDark();
+    }
+
+    /**
      * Top position of this view relative to its parent.
      *
      * @return The top of this view, in pixels.
@@ -17932,7 +17975,7 @@
         rebuildOutline();
 
         if (isFocused()) {
-            InputMethodManager imm = InputMethodManager.peekInstance();
+            InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
             if (imm != null) {
                 imm.focusIn(this);
             }
@@ -18406,7 +18449,7 @@
      * communicate with the window manager.
      * @return the session object to communicate with the window manager
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     /*package*/ IWindowSession getWindowSession() {
         return mAttachInfo != null ? mAttachInfo.mSession : null;
     }
@@ -18515,7 +18558,7 @@
         onDetachedFromWindow();
         onDetachedFromWindowInternal();
 
-        InputMethodManager imm = InputMethodManager.peekInstance();
+        InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
         if (imm != null) {
             imm.onViewDetachedFromWindow(this);
         }
@@ -20561,7 +20604,8 @@
      */
     private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) {
         if (renderNode == null) {
-            renderNode = RenderNode.create(drawable.getClass().getName(), this);
+            renderNode = RenderNode.create(drawable.getClass().getName(),
+                    new ViewAnimationHostBridge(this));
             renderNode.setUsageHint(RenderNode.USAGE_BACKGROUND);
         }
 
diff --git a/core/java/android/view/ViewAnimationHostBridge.java b/core/java/android/view/ViewAnimationHostBridge.java
new file mode 100644
index 0000000..58f555d
--- /dev/null
+++ b/core/java/android/view/ViewAnimationHostBridge.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+/**
+ * Maps a View to a RenderNode's AnimationHost
+ *
+ * @hide
+ */
+public class ViewAnimationHostBridge implements RenderNode.AnimationHost {
+    private final View mView;
+
+    /**
+     * @param view the View to bridge to an AnimationHost
+     */
+    public ViewAnimationHostBridge(View view) {
+        mView = view;
+    }
+
+    @Override
+    public void registerAnimatingRenderNode(RenderNode animator) {
+        mView.mAttachInfo.mViewRootImpl.registerAnimatingRenderNode(animator);
+    }
+
+    @Override
+    public void registerVectorDrawableAnimator(NativeVectorDrawableAnimator animator) {
+        mView.mAttachInfo.mViewRootImpl.registerVectorDrawableAnimator(animator);
+    }
+
+    @Override
+    public boolean isAttached() {
+        return mView.mAttachInfo != null;
+    }
+}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 0119d2e..1b3e62d 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -8116,7 +8116,7 @@
         /**
          * Sets the margins, in pixels. A call to {@link android.view.View#requestLayout()} needs
          * to be done so that the new margins are taken into account. Left and right margins may be
-         * overriden by {@link android.view.View#requestLayout()} depending on layout direction.
+         * overridden by {@link android.view.View#requestLayout()} depending on layout direction.
          * Margin values should be positive.
          *
          * @param left the left margin size
@@ -8146,8 +8146,8 @@
         /**
          * Sets the relative margins, in pixels. A call to {@link android.view.View#requestLayout()}
          * needs to be done so that the new relative margins are taken into account. Left and right
-         * margins may be overriden by {@link android.view.View#requestLayout()} depending on layout
-         * direction. Margin values should be positive.
+         * margins may be overridden by {@link android.view.View#requestLayout()} depending on
+         * layout direction. Margin values should be positive.
          *
          * @param start the start margin size
          * @param top the top margin size
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 16d202b..bef8e8f 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -43,6 +43,7 @@
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Matrix;
@@ -52,7 +53,6 @@
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.Region;
-import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManager.DisplayListener;
@@ -239,6 +239,12 @@
     final ArrayList<WindowCallbacks> mWindowCallbacks = new ArrayList<>();
     @UnsupportedAppUsage
     final Context mContext;
+    /**
+     * TODO(b/116349163): Check if we can merge this into {@link #mContext}.
+     */
+    @NonNull
+    private Context mDisplayContext;
+
     @UnsupportedAppUsage
     final IWindowSession mWindowSession;
     @NonNull Display mDisplay;
@@ -532,6 +538,7 @@
 
     public ViewRootImpl(Context context, Display display) {
         mContext = context;
+        mDisplayContext = context.createDisplayContext(display);
         mWindowSession = WindowManagerGlobal.getWindowSession();
         mDisplay = display;
         mBasePackageName = context.getBasePackageName();
@@ -984,6 +991,9 @@
         ThreadedRenderer.invokeFunctor(functor, waitForCompletion);
     }
 
+    /**
+     * @param animator animator to register with the hardware renderer
+     */
     public void registerAnimatingRenderNode(RenderNode animator) {
         if (mAttachInfo.mThreadedRenderer != null) {
             mAttachInfo.mThreadedRenderer.registerAnimatingRenderNode(animator);
@@ -995,8 +1005,10 @@
         }
     }
 
-    public void registerVectorDrawableAnimator(
-            AnimatedVectorDrawable.VectorDrawableAnimatorRT animator) {
+    /**
+     * @param animator animator to register with the hardware renderer
+     */
+    public void registerVectorDrawableAnimator(NativeVectorDrawableAnimator animator) {
         if (mAttachInfo.mThreadedRenderer != null) {
             mAttachInfo.mThreadedRenderer.registerVectorDrawableAnimator(animator);
         }
@@ -1066,6 +1078,7 @@
                 mAttachInfo.mThreadedRenderer = ThreadedRenderer.create(mContext, translucent,
                         attrs.getTitle().toString());
                 mAttachInfo.mThreadedRenderer.setWideGamut(wideGamut);
+                updateForceDarkMode();
                 if (mAttachInfo.mThreadedRenderer != null) {
                     mAttachInfo.mHardwareAccelerated =
                             mAttachInfo.mHardwareAccelerationRequested = true;
@@ -1074,6 +1087,27 @@
         }
     }
 
+    private int getNightMode() {
+        return mContext.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
+    }
+
+    private void updateForceDarkMode() {
+        if (mAttachInfo.mThreadedRenderer == null) return;
+
+        boolean nightMode = getNightMode() == Configuration.UI_MODE_NIGHT_YES;
+        TypedArray a = mContext.obtainStyledAttributes(R.styleable.Theme);
+        boolean isLightTheme = a.getBoolean(R.styleable.Theme_isLightTheme, false);
+        a.recycle();
+
+        boolean changed = mAttachInfo.mThreadedRenderer.setForceDark(nightMode);
+        changed |= mAttachInfo.mThreadedRenderer.getRootNode().setAllowForceDark(isLightTheme);
+
+        if (changed) {
+            // TODO: Don't require regenerating all display lists to apply this setting
+            invalidateWorld(mView);
+        }
+    }
+
     @UnsupportedAppUsage
     public View getView() {
         return mView;
@@ -1249,6 +1283,7 @@
         } else {
             mDisplay = preferredDisplay;
         }
+        mDisplayContext = mContext.createDisplayContext(mDisplay);
     }
 
     void pokeDrawLockIfNeeded() {
@@ -2579,7 +2614,7 @@
                     .mayUseInputMethod(mWindowAttributes.flags);
             if (imTarget != mLastWasImTarget) {
                 mLastWasImTarget = imTarget;
-                InputMethodManager imm = InputMethodManager.peekInstance();
+                InputMethodManager imm = mDisplayContext.getSystemService(InputMethodManager.class);
                 if (imm != null && imTarget) {
                     imm.onPreWindowFocus(mView, hasWindowFocus);
                     imm.onPostWindowFocus(mView, mView.findFocus(),
@@ -2695,7 +2730,7 @@
             mLastWasImTarget = WindowManager.LayoutParams
                     .mayUseInputMethod(mWindowAttributes.flags);
 
-            InputMethodManager imm = InputMethodManager.peekInstance();
+            InputMethodManager imm = mDisplayContext.getSystemService(InputMethodManager.class);
             if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
                 imm.onPreWindowFocus(mView, hasWindowFocus);
             }
@@ -4065,6 +4100,8 @@
             mForceNextWindowRelayout = true;
             requestLayout();
         }
+
+        updateForceDarkMode();
     }
 
     /**
@@ -4329,7 +4366,8 @@
                     enqueueInputEvent(event, null, 0, true);
                 } break;
                 case MSG_CHECK_FOCUS: {
-                    InputMethodManager imm = InputMethodManager.peekInstance();
+                    InputMethodManager imm =
+                            mDisplayContext.getSystemService(InputMethodManager.class);
                     if (imm != null) {
                         imm.checkFocus();
                     }
@@ -4871,7 +4909,7 @@
         @Override
         protected int onProcess(QueuedInputEvent q) {
             if (mLastWasImTarget && !isInLocalFocusMode()) {
-                InputMethodManager imm = InputMethodManager.peekInstance();
+                InputMethodManager imm = mDisplayContext.getSystemService(InputMethodManager.class);
                 if (imm != null) {
                     final InputEvent event = q.mEvent;
                     if (DEBUG_IMF) Log.v(mTag, "Sending input event to IME: " + event);
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index f436962..982737a 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -25,6 +25,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StyleRes;
+import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.app.WindowConfiguration;
 import android.content.Context;
@@ -422,7 +423,7 @@
          * @return boolean You must return true for the panel to be displayed;
          *         if you return false it will not be shown.
          */
-        public boolean onCreatePanelMenu(int featureId, Menu menu);
+        boolean onCreatePanelMenu(int featureId, @NonNull Menu menu);
 
         /**
          * Prepare a panel to be displayed.  This is called right before the
@@ -438,7 +439,7 @@
          *
          * @see #onCreatePanelView
          */
-        public boolean onPreparePanel(int featureId, View view, Menu menu);
+        boolean onPreparePanel(int featureId, @Nullable View view, @NonNull Menu menu);
 
         /**
          * Called when a panel's menu is opened by the user. This may also be
@@ -450,7 +451,7 @@
          * @return Return true to allow the menu to open, or false to prevent
          *         the menu from opening.
          */
-        public boolean onMenuOpened(int featureId, Menu menu);
+        boolean onMenuOpened(int featureId, @NonNull Menu menu);
 
         /**
          * Called when a panel's menu item has been selected by the user.
@@ -462,7 +463,7 @@
          *         false to perform the normal menu handling (calling its
          *         Runnable or sending a Message to its target Handler).
          */
-        public boolean onMenuItemSelected(int featureId, MenuItem item);
+        boolean onMenuItemSelected(int featureId, @NonNull MenuItem item);
 
         /**
          * This is called whenever the current window attributes change.
@@ -512,7 +513,7 @@
          * @param menu If onCreatePanelView() returned null, this is the Menu
          *            being displayed in the panel.
          */
-        public void onPanelClosed(int featureId, Menu menu);
+        void onPanelClosed(int featureId, @NonNull Menu menu);
 
         /**
          * Called when the user signals the desire to start a search.
@@ -1079,8 +1080,18 @@
         setFlags(flags, flags);
     }
 
-    /** @hide */
-    @UnsupportedAppUsage
+    /**
+     * Add private flag bits.
+     *
+     * <p>Refer to the individual flags for the permissions needed.
+     *
+     * <p>Note: Only for updateable system components (aka. mainline modules)
+     *
+     * @param flags The flag bits to add.
+     *
+     * @hide
+     */
+    @SystemApi
     public void addPrivateFlags(int flags) {
         setPrivateFlags(flags, flags);
     }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 0404df0..742df5e8 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1668,6 +1668,7 @@
          * this window is visible.
          * @hide
          */
+        @SystemApi
         @RequiresPermission(permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS)
         public static final int PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS = 0x00080000;
 
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index d810067..46aea80 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.res.Configuration;
+import android.os.Build;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -195,7 +196,10 @@
         synchronized (WindowManagerGlobal.class) {
             if (sWindowSession == null) {
                 try {
-                    InputMethodManager imm = InputMethodManager.getInstance();
+                    // Emulate the legacy behavior.  The global instance of InputMethodManager
+                    // was instantiated here.
+                    // TODO(b/116157766): Remove this hack after cleaning up @UnsupportedAppUsage
+                    InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary();
                     IWindowManager windowManager = getWindowManagerService();
                     sWindowSession = windowManager.openSession(
                             new IWindowSessionCallback.Stub() {
@@ -203,8 +207,7 @@
                                 public void onAnimatorScaleChanged(float scale) {
                                     ValueAnimator.setDurationScale(scale);
                                 }
-                            },
-                            imm.getClient(), imm.getInputContext());
+                            });
                 } catch (RemoteException e) {
                     throw e.rethrowFromSystemServer();
                 }
@@ -213,7 +216,7 @@
         }
     }
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public static IWindowSession peekWindowSession() {
         synchronized (WindowManagerGlobal.class) {
             return sWindowSession;
@@ -467,7 +470,7 @@
         View view = root.getView();
 
         if (view != null) {
-            InputMethodManager imm = InputMethodManager.getInstance();
+            InputMethodManager imm = view.getContext().getSystemService(InputMethodManager.class);
             if (imm != null) {
                 imm.windowDismissed(mViews.get(index).getWindowToken());
             }
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 3eca854..dccf9d4 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -761,7 +762,7 @@
     private CharSequence mPackageName;
     private long mEventTime;
     int mMovementGranularity;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     int mAction;
     int mContentChangeTypes;
     int mWindowChangeTypes;
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index a3fa2ce..4d3f0fc 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -632,6 +632,8 @@
 
     private static final int BOOLEAN_PROPERTY_IS_HEADING = 0x0200000;
 
+    private static final int BOOLEAN_PROPERTY_IS_TEXT_ENTRY_KEY = 0x0400000;
+
     /**
      * Bits that provide the id of a virtual descendant of a view.
      */
@@ -2461,6 +2463,30 @@
     }
 
     /**
+     * Returns whether node represents a text entry key that is part of a keyboard or keypad.
+     *
+     * @return {@code true} if the node is a text entry key., {@code false} otherwise.
+     */
+    public boolean isTextEntryKey() {
+        return getBooleanProperty(BOOLEAN_PROPERTY_IS_TEXT_ENTRY_KEY);
+    }
+
+    /**
+     * Sets whether the node represents a text entry key that is part of a keyboard or keypad.
+     *
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     *
+     * @param isTextEntryKey {@code true} if the node is a text entry key, {@code false} otherwise.
+     */
+    public void setTextEntryKey(boolean isTextEntryKey) {
+        setBooleanProperty(BOOLEAN_PROPERTY_IS_TEXT_ENTRY_KEY, isTextEntryKey);
+    }
+
+    /**
      * Gets the package this node comes from.
      *
      * @return The package name.
diff --git a/core/java/android/view/animation/DecelerateInterpolator.java b/core/java/android/view/animation/DecelerateInterpolator.java
index f89743c..2d1249d 100644
--- a/core/java/android/view/animation/DecelerateInterpolator.java
+++ b/core/java/android/view/animation/DecelerateInterpolator.java
@@ -41,8 +41,8 @@
      * Constructor
      *
      * @param factor Degree to which the animation should be eased. Setting factor to 1.0f produces
-     *        an upside-down y=x^2 parabola. Increasing factor above 1.0f makes exaggerates the
-     *        ease-out effect (i.e., it starts even faster and ends evens slower)
+     *        an upside-down y=x^2 parabola. Increasing factor above 1.0f exaggerates the
+     *        ease-out effect (i.e., it starts even faster and ends evens slower).
      */
     public DecelerateInterpolator(float factor) {
         mFactor = factor;
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 9419e93..7abe19e79 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -45,6 +45,7 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
+import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Choreographer;
 import android.view.KeyEvent;
@@ -300,6 +301,14 @@
      */
     public static final int STATE_UNKNOWN_COMPAT_MODE = 5;
 
+    /**
+     * Same as {@link #STATE_UNKNOWN}, but used on
+     * {@link AutofillManagerClient#setSessionFinished(int)} when the session was finished because
+     * the service failed to fullfil a request.
+     *
+     * @hide
+     */
+    public static final int STATE_UNKNOWN_FAILED = 6;
 
     /**
      * Timeout in ms for calls to the field classification service.
@@ -559,6 +568,9 @@
             // different bridge based on which activity is currently focused
             // in the current process. Since compat would be rarely used, just
             // create and register a new instance every time.
+            if (sDebug) {
+                Slog.d(TAG, "creating CompatibilityBridge for " + mContext);
+            }
             mCompatibilityBridge = new CompatibilityBridge();
         }
     }
@@ -2019,8 +2031,10 @@
      * @param newState {@link #STATE_FINISHED} (because the autofill service returned a {@code null}
      *  FillResponse), {@link #STATE_UNKNOWN} (because the session was removed),
      *  {@link #STATE_UNKNOWN_COMPAT_MODE} (beucase the session was finished when the URL bar
-     *  changed on compat mode), or {@link #STATE_DISABLED_BY_SERVICE} (because the autofill service
-     *  disabled further autofill requests for the activity).
+     *  changed on compat mode), {@link #STATE_UNKNOWN_FAILED} (because the session was finished
+     *  when the service failed to fullfil the request, or {@link #STATE_DISABLED_BY_SERVICE}
+     *  (because the autofill service or {@link #STATE_DISABLED_BY_SERVICE} (because the autofill
+     *  service disabled further autofill requests for the activity).
      */
     private void setSessionFinished(int newState) {
         synchronized (mLock) {
@@ -2028,7 +2042,7 @@
                 Log.v(TAG, "setSessionFinished(): from " + getStateAsStringLocked() + " to "
                         + getStateAsString(newState));
             }
-            if (newState == STATE_UNKNOWN_COMPAT_MODE) {
+            if (newState == STATE_UNKNOWN_COMPAT_MODE || newState == STATE_UNKNOWN_FAILED) {
                 resetSessionLocked(/* resetEnteredIds= */ true);
                 mState = STATE_UNKNOWN;
             } else {
@@ -2225,6 +2239,8 @@
                 return "DISABLED_BY_SERVICE";
             case STATE_UNKNOWN_COMPAT_MODE:
                 return "UNKNOWN_COMPAT_MODE";
+            case STATE_UNKNOWN_FAILED:
+                return "UNKNOWN_FAILED";
             default:
                 return "INVALID:" + state;
         }
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index c51c5e2..ca2ccaf 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -57,7 +57,7 @@
 import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
 import android.view.autofill.AutofillManager;
 
-import com.android.internal.inputmethod.InputMethodPrivilegedOperations;
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.view.IInputConnectionWrapper;
@@ -70,6 +70,7 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.lang.reflect.Proxy;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -226,6 +227,54 @@
 
     static final String PENDING_EVENT_COUNTER = "aq:imm";
 
+    /**
+     * Ensures that {@link #sInstance} becomes non-{@code null} for application that have directly
+     * or indirectly relied on {@link #sInstance} via reflection or something like that.
+     *
+     * <p>Here are scenarios we know and there could be more scenarios we are not
+     * aware of right know.</p>
+     *
+     * <ul>
+     *     <li>Apps that directly access {@link #sInstance} via reflection, which is currently
+     *     allowed because of {@link UnsupportedAppUsage} annotation.  Currently
+     *     {@link android.view.WindowManagerGlobal#getWindowSession()} is likely to guarantee that
+     *     {@link #sInstance} is not {@code null} when such an app is accessing it, but removing
+     *     that code from {@link android.view.WindowManagerGlobal#getWindowSession()} can reveal
+     *     untested code paths in their apps, which probably happen in an early startup time of that
+     *     app.</li>
+     *     <li>Apps that directly access {@link #peekInstance()} via reflection, which is currently
+     *     allowed because of {@link UnsupportedAppUsage} annotation.  Currently
+     *     {@link android.view.WindowManagerGlobal#getWindowSession()} is likely to guarantee that
+     *     {@link #peekInstance()} returns non-{@code null} object when such an app is calling
+     *     {@link #peekInstance()}, but removing that code from
+     *     {@link android.view.WindowManagerGlobal#getWindowSession()} can reveal untested code
+     *     paths in their apps, which probably happen in an early startup time of that app. The good
+     *     news is that unlike {@link #sInstance}'s case we can at least work around this scenario
+     *     by changing the semantics of {@link #peekInstance()}, which is currently defined as
+     *     "retrieve the global {@link InputMethodManager} instance, if it exists" to something that
+     *     always returns non-{@code null} {@link InputMethodManager}.  However, introducing such an
+     *     workaround can also trigger different compatibility issues if {@link #peekInstance()} was
+     *     called before {@link android.view.WindowManagerGlobal#getWindowSession()} and it expected
+     *     {@link #peekInstance()} to return {@code null} as written in the JavaDoc.</li>
+     * </ul>
+     *
+     * <p>Since this is purely a compatibility hack, this method must be used only from
+     * {@link android.view.WindowManagerGlobal#getWindowSession()} and {@link #getInstance()}.</p>
+     *
+     * <p>TODO(Bug 116157766): Remove this method once we clean up {@link UnsupportedAppUsage}.</p>
+     * @hide
+     */
+    public static void ensureDefaultInstanceForDefaultDisplayIfNecessary() {
+        getInstanceInternal();
+    }
+
+    private static final Object sLock = new Object();
+
+    /**
+     * @deprecated This cannot be compatible with multi-display. Please do not use this.
+     */
+    @Deprecated
+    @GuardedBy("sLock")
     @UnsupportedAppUsage
     static InputMethodManager sInstance;
 
@@ -336,7 +385,7 @@
     /**
      * The InputConnection that was last retrieved from the served view.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     ControlledInputConnectionWrapper mServedInputConnectionWrapper;
     /**
      * The completions that were last provided by the served view.
@@ -387,9 +436,6 @@
     final Pool<PendingEvent> mPendingEventPool = new SimplePool<>(20);
     final SparseArray<PendingEvent> mPendingEvents = new SparseArray<>(20);
 
-    private final InputMethodPrivilegedOperationsRegistry mPrivOpsRegistry =
-            new InputMethodPrivilegedOperationsRegistry();
-
     // -----------------------------------------------------------
 
     static final int MSG_DUMP = 1;
@@ -632,13 +678,63 @@
 
     final InputConnection mDummyInputConnection = new BaseInputConnection(this, false);
 
-    InputMethodManager(Looper looper) throws ServiceNotFoundException {
-        this(IInputMethodManager.Stub.asInterface(
-                ServiceManager.getServiceOrThrow(Context.INPUT_METHOD_SERVICE)), looper);
+    /**
+     * For layoutlib to clean up static objects inside {@link InputMethodManager}.
+     */
+    static void tearDownEditMode() {
+        if (!isInEditMode()) {
+            throw new UnsupportedOperationException(
+                    "This method must be called only from layoutlib");
+        }
+        synchronized (sLock) {
+            sInstance = null;
+        }
     }
 
-    InputMethodManager(IInputMethodManager service, Looper looper) {
-        mService = service;
+    /**
+     * For layoutlib to override this method to return {@code true}.
+     *
+     * @return {@code true} if the process is running for developer tools
+     * @see View#isInEditMode()
+     */
+    private static boolean isInEditMode() {
+        return false;
+    }
+
+    private static IInputMethodManager getIInputMethodManager() throws ServiceNotFoundException {
+        if (!isInEditMode()) {
+            return IInputMethodManager.Stub.asInterface(
+                    ServiceManager.getServiceOrThrow(Context.INPUT_METHOD_SERVICE));
+        }
+        // If InputMethodManager is running for layoutlib, stub out IPCs into IMMS.
+        final Class<IInputMethodManager> c = IInputMethodManager.class;
+        return (IInputMethodManager) Proxy.newProxyInstance(c.getClassLoader(),
+                new Class[]{c}, (proxy, method, args) -> {
+                    final Class<?> returnType = method.getReturnType();
+                    if (returnType == boolean.class) {
+                        return false;
+                    } else if (returnType == int.class) {
+                        return 0;
+                    } else if (returnType == long.class) {
+                        return 0L;
+                    } else if (returnType == short.class) {
+                        return 0;
+                    } else if (returnType == char.class) {
+                        return 0;
+                    } else if (returnType == byte.class) {
+                        return 0;
+                    } else if (returnType == float.class) {
+                        return 0f;
+                    } else if (returnType == double.class) {
+                        return 0.0;
+                    } else {
+                        return null;
+                    }
+                });
+    }
+
+    InputMethodManager(Looper looper) throws ServiceNotFoundException {
+        mService = getIInputMethodManager();
         mMainLooper = looper;
         mH = new H(looper);
         mIInputContext = new ControlledInputConnectionWrapper(looper,
@@ -646,17 +742,20 @@
     }
 
     /**
-     * Retrieve the global InputMethodManager instance, creating it if it
-     * doesn't already exist.
+     * Retrieve the global {@link InputMethodManager} instance, creating it if it doesn't already
+     * exist.
+     *
+     * @return global {@link InputMethodManager} instance
      * @hide
      */
-    @UnsupportedAppUsage
-    public static InputMethodManager getInstance() {
-        synchronized (InputMethodManager.class) {
+    public static InputMethodManager getInstanceInternal() {
+        synchronized (sLock) {
             if (sInstance == null) {
                 try {
-                    sInstance = new InputMethodManager(Looper.getMainLooper());
-                } catch (ServiceNotFoundException e) {
+                    final InputMethodManager imm = new InputMethodManager(Looper.getMainLooper());
+                    imm.mService.addClient(imm.mClient, imm.mIInputContext);
+                    sInstance = imm;
+                } catch (ServiceNotFoundException | RemoteException e) {
                     throw new IllegalStateException(e);
                 }
             }
@@ -665,13 +764,42 @@
     }
 
     /**
-     * Private optimization: retrieve the global InputMethodManager instance,
-     * if it exists.
+     * Deprecated. Do not use.
+     *
+     * @return global {@link InputMethodManager} instance
+     * @deprecated Use {@link Context#getSystemService(Class)} instead. This method cannot fully
+     *             support multi-display scenario.
      * @hide
      */
+    @Deprecated
+    @UnsupportedAppUsage
+    public static InputMethodManager getInstance() {
+        Log.w(TAG, "InputMethodManager.getInstance() is deprecated because it cannot be"
+                        + " compatible with multi-display."
+                        + " Use context.getSystemService(InputMethodManager.class) instead.",
+                new Throwable());
+        ensureDefaultInstanceForDefaultDisplayIfNecessary();
+        return peekInstance();
+    }
+
+    /**
+     * Deprecated. Do not use.
+     *
+     * @return {@link #sInstance}
+     * @deprecated Use {@link Context#getSystemService(Class)} instead. This method cannot fully
+     *             support multi-display scenario.
+     * @hide
+     */
+    @Deprecated
     @UnsupportedAppUsage
     public static InputMethodManager peekInstance() {
-        return sInstance;
+        Log.w(TAG, "InputMethodManager.peekInstance() is deprecated because it cannot be"
+                        + " compatible with multi-display."
+                        + " Use context.getSystemService(InputMethodManager.class) instead.",
+                new Throwable());
+        synchronized (sLock) {
+            return sInstance;
+        }
     }
 
     /** @hide */
@@ -739,7 +867,7 @@
      */
     @Deprecated
     public void showStatusIcon(IBinder imeToken, String packageName, @DrawableRes int iconId) {
-        mPrivOpsRegistry.get(imeToken).updateStatusIcon(packageName, iconId);
+        InputMethodPrivilegedOperationsRegistry.get(imeToken).updateStatusIcon(packageName, iconId);
     }
 
     /**
@@ -749,7 +877,7 @@
      */
     @Deprecated
     public void hideStatusIcon(IBinder imeToken) {
-        mPrivOpsRegistry.get(imeToken).updateStatusIcon(null, 0);
+        InputMethodPrivilegedOperationsRegistry.get(imeToken).updateStatusIcon(null, 0);
     }
 
     /** @hide */
@@ -1350,6 +1478,10 @@
                     mServedView.getWindowToken() == appWindowToken) {
                 finishInputLocked();
             }
+            if (mCurRootView != null &&
+                    mCurRootView.getWindowToken() == appWindowToken) {
+                mCurRootView = null;
+            }
         }
     }
 
@@ -1790,7 +1922,7 @@
     public void setInputMethod(IBinder token, String id) {
         if (token == null) {
             // Note: null token is allowed for callers that have WRITE_SECURE_SETTINGS permission.
-            // Thus we cannot always rely on mPrivOpsRegistry unfortunately.
+            // Thus we cannot always rely on InputMethodPrivilegedOperationsRegistry unfortunately.
             // TODO(Bug 114488811): Consider deprecating null token rule.
             try {
                 mService.setInputMethod(token, id);
@@ -1799,7 +1931,7 @@
             }
             return;
         }
-        mPrivOpsRegistry.get(token).setInputMethod(id);
+        InputMethodPrivilegedOperationsRegistry.get(token).setInputMethod(id);
     }
 
     /**
@@ -1819,7 +1951,7 @@
     public void setInputMethodAndSubtype(IBinder token, String id, InputMethodSubtype subtype) {
         if (token == null) {
             // Note: null token is allowed for callers that have WRITE_SECURE_SETTINGS permission.
-            // Thus we cannot always rely on mPrivOpsRegistry unfortunately.
+            // Thus we cannot always rely on InputMethodPrivilegedOperationsRegistry unfortunately.
             // TODO(Bug 114488811): Consider deprecating null token rule.
             try {
                 mService.setInputMethodAndSubtype(token, id, subtype);
@@ -1828,7 +1960,7 @@
             }
             return;
         }
-        mPrivOpsRegistry.get(token).setInputMethodAndSubtype(id, subtype);
+        InputMethodPrivilegedOperationsRegistry.get(token).setInputMethodAndSubtype(id, subtype);
     }
 
     /**
@@ -1848,7 +1980,7 @@
      */
     @Deprecated
     public void hideSoftInputFromInputMethod(IBinder token, int flags) {
-        mPrivOpsRegistry.get(token).hideMySoftInput(flags);
+        InputMethodPrivilegedOperationsRegistry.get(token).hideMySoftInput(flags);
     }
 
     /**
@@ -1869,7 +2001,7 @@
      */
     @Deprecated
     public void showSoftInputFromInputMethod(IBinder token, int flags) {
-        mPrivOpsRegistry.get(token).showMySoftInput(flags);
+        InputMethodPrivilegedOperationsRegistry.get(token).showMySoftInput(flags);
     }
 
     /**
@@ -2229,7 +2361,7 @@
     public boolean switchToLastInputMethod(IBinder imeToken) {
         if (imeToken == null) {
             // Note: null token is allowed for callers that have WRITE_SECURE_SETTINGS permission.
-            // Thus we cannot always rely on mPrivOpsRegistry unfortunately.
+            // Thus we cannot always rely on InputMethodPrivilegedOperationsRegistry unfortunately.
             // TODO(Bug 114488811): Consider deprecating null token rule.
             try {
                 return mService.switchToPreviousInputMethod(imeToken);
@@ -2237,7 +2369,7 @@
                 throw e.rethrowFromSystemServer();
             }
         }
-        return mPrivOpsRegistry.get(imeToken).switchToPreviousInputMethod();
+        return InputMethodPrivilegedOperationsRegistry.get(imeToken).switchToPreviousInputMethod();
     }
 
     /**
@@ -2257,7 +2389,7 @@
     public boolean switchToNextInputMethod(IBinder imeToken, boolean onlyCurrentIme) {
         if (imeToken == null) {
             // Note: null token is allowed for callers that have WRITE_SECURE_SETTINGS permission.
-            // Thus we cannot always rely on mPrivOpsRegistry unfortunately.
+            // Thus we cannot always rely on InputMethodPrivilegedOperationsRegistry unfortunately.
             // TODO(Bug 114488811): Consider deprecating null token rule.
             try {
                 return mService.switchToNextInputMethod(imeToken, onlyCurrentIme);
@@ -2265,7 +2397,8 @@
                 throw e.rethrowFromSystemServer();
             }
         }
-        return mPrivOpsRegistry.get(imeToken).switchToNextInputMethod(onlyCurrentIme);
+        return InputMethodPrivilegedOperationsRegistry.get(imeToken)
+                .switchToNextInputMethod(onlyCurrentIme);
     }
 
     /**
@@ -2284,7 +2417,8 @@
      */
     @Deprecated
     public boolean shouldOfferSwitchingToNextInputMethod(IBinder imeToken) {
-        return mPrivOpsRegistry.get(imeToken).shouldOfferSwitchingToNextInputMethod();
+        return InputMethodPrivilegedOperationsRegistry.get(imeToken)
+                .shouldOfferSwitchingToNextInputMethod();
     }
 
     /**
@@ -2420,34 +2554,4 @@
         sb.append(",temporaryDetach=" + view.isTemporarilyDetached());
         return sb.toString();
     }
-
-    /**
-     * Called by {@link InputMethodService} so that API calls to deprecated ones defined in this
-     * class can be forwarded to {@link InputMethodPrivilegedOperations}.
-     *
-     * <p>Note: this method does not hold strong references to {@code token} and {@code ops}. The
-     * registry entry will be automatically cleared after {@code token} is garbage collected.</p>
-     *
-     * @param token IME token that is associated with {@code ops}
-     * @param ops {@link InputMethodPrivilegedOperations} that is associated with {@code token}
-     * @hide
-     */
-    public void registerInputMethodPrivOps(IBinder token, InputMethodPrivilegedOperations ops) {
-        mPrivOpsRegistry.put(token, ops);
-    }
-
-    /**
-     * Called from {@link InputMethodService#onDestroy()} to make sure that deprecated IME APIs
-     * defined in this class can no longer access to {@link InputMethodPrivilegedOperations}.
-     *
-     * <p>Note: Calling this method is optional, but at least gives more explict error message in
-     * logcat when IME developers are doing something unsupported (e.g. trying to call IME APIs
-     * after {@link InputMethodService#onDestroy()}).</p>
-     *
-     * @param token IME token to be removed.
-     * @hide
-     */
-    public void unregisterInputMethodPrivOps(IBinder token) {
-        mPrivOpsRegistry.remove(token);
-    }
 }
diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java
index a7d7a8d..14c879e 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtype.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtype.java
@@ -28,7 +28,7 @@
 import android.text.TextUtils;
 import android.util.Slog;
 
-import com.android.internal.inputmethod.InputMethodUtils;
+import com.android.internal.inputmethod.SubtypeLocaleUtils;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -384,7 +384,7 @@
             if (!TextUtils.isEmpty(mSubtypeLanguageTag)) {
                 mCachedLocaleObj = Locale.forLanguageTag(mSubtypeLanguageTag);
             } else {
-                mCachedLocaleObj = InputMethodUtils.constructLocaleFromString(mSubtypeLocale);
+                mCachedLocaleObj = SubtypeLocaleUtils.constructLocaleFromString(mSubtypeLocale);
             }
             return mCachedLocaleObj;
         }
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 29339e9..3e240cf 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -44,6 +44,8 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
 
+import com.google.android.textclassifier.AnnotatorModel;
+
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -92,7 +94,7 @@
     @GuardedBy("mLock") // Do not access outside this lock.
     private ModelFile mModel;
     @GuardedBy("mLock") // Do not access outside this lock.
-    private TextClassifierImplNative mNative;
+    private AnnotatorModel mNative;
 
     private final Object mLoggerLock = new Object();
     @GuardedBy("mLoggerLock") // Do not access outside this lock.
@@ -125,7 +127,7 @@
                     && rangeLength <= mSettings.getSuggestSelectionMaxRangeLength()) {
                 final String localesString = concatenateLocales(request.getDefaultLocales());
                 final ZonedDateTime refTime = ZonedDateTime.now();
-                final TextClassifierImplNative nativeImpl = getNative(request.getDefaultLocales());
+                final AnnotatorModel nativeImpl = getNative(request.getDefaultLocales());
                 final int start;
                 final int end;
                 if (mSettings.isModelDarkLaunchEnabled() && !request.isDarkLaunchAllowed()) {
@@ -134,7 +136,7 @@
                 } else {
                     final int[] startEnd = nativeImpl.suggestSelection(
                             string, request.getStartIndex(), request.getEndIndex(),
-                            new TextClassifierImplNative.SelectionOptions(localesString));
+                            new AnnotatorModel.SelectionOptions(localesString));
                     start = startEnd[0];
                     end = startEnd[1];
                 }
@@ -142,10 +144,10 @@
                         && start >= 0 && end <= string.length()
                         && start <= request.getStartIndex() && end >= request.getEndIndex()) {
                     final TextSelection.Builder tsBuilder = new TextSelection.Builder(start, end);
-                    final TextClassifierImplNative.ClassificationResult[] results =
+                    final AnnotatorModel.ClassificationResult[] results =
                             nativeImpl.classifyText(
                                     string, start, end,
-                                    new TextClassifierImplNative.ClassificationOptions(
+                                    new AnnotatorModel.ClassificationOptions(
                                             refTime.toInstant().toEpochMilli(),
                                             refTime.getZone().getId(),
                                             localesString));
@@ -184,11 +186,11 @@
                 final String localesString = concatenateLocales(request.getDefaultLocales());
                 final ZonedDateTime refTime = request.getReferenceTime() != null
                         ? request.getReferenceTime() : ZonedDateTime.now();
-                final TextClassifierImplNative.ClassificationResult[] results =
+                final AnnotatorModel.ClassificationResult[] results =
                         getNative(request.getDefaultLocales())
                                 .classifyText(
                                         string, request.getStartIndex(), request.getEndIndex(),
-                                        new TextClassifierImplNative.ClassificationOptions(
+                                        new AnnotatorModel.ClassificationOptions(
                                                 refTime.toInstant().toEpochMilli(),
                                                 refTime.getZone().getId(),
                                                 localesString));
@@ -228,17 +230,17 @@
                     ? request.getEntityConfig().resolveEntityListModifications(
                             getEntitiesForHints(request.getEntityConfig().getHints()))
                     : mSettings.getEntityListDefault();
-            final TextClassifierImplNative nativeImpl =
+            final AnnotatorModel nativeImpl =
                     getNative(request.getDefaultLocales());
-            final TextClassifierImplNative.AnnotatedSpan[] annotations =
+            final AnnotatorModel.AnnotatedSpan[] annotations =
                     nativeImpl.annotate(
                         textString,
-                        new TextClassifierImplNative.AnnotationOptions(
+                        new AnnotatorModel.AnnotationOptions(
                                 refTime.toInstant().toEpochMilli(),
                                         refTime.getZone().getId(),
                                 concatenateLocales(request.getDefaultLocales())));
-            for (TextClassifierImplNative.AnnotatedSpan span : annotations) {
-                final TextClassifierImplNative.ClassificationResult[] results =
+            for (AnnotatorModel.AnnotatedSpan span : annotations) {
+                final AnnotatorModel.ClassificationResult[] results =
                         span.getClassification();
                 if (results.length == 0
                         || !entitiesToIdentify.contains(results[0].getCollection())) {
@@ -297,7 +299,7 @@
         }
     }
 
-    private TextClassifierImplNative getNative(LocaleList localeList)
+    private AnnotatorModel getNative(LocaleList localeList)
             throws FileNotFoundException {
         synchronized (mLock) {
             localeList = localeList == null ? LocaleList.getEmptyLocaleList() : localeList;
@@ -310,7 +312,7 @@
                 destroyNativeIfExistsLocked();
                 final ParcelFileDescriptor fd = ParcelFileDescriptor.open(
                         new File(bestModel.getPath()), ParcelFileDescriptor.MODE_READ_ONLY);
-                mNative = new TextClassifierImplNative(fd.getFd());
+                mNative = new AnnotatorModel(fd.getFd());
                 closeAndLogError(fd);
                 mModel = bestModel;
             }
@@ -398,14 +400,14 @@
     }
 
     private TextClassification createClassificationResult(
-            TextClassifierImplNative.ClassificationResult[] classifications,
+            AnnotatorModel.ClassificationResult[] classifications,
             String text, int start, int end, @Nullable Instant referenceTime) {
         final String classifiedText = text.substring(start, end);
         final TextClassification.Builder builder = new TextClassification.Builder()
                 .setText(classifiedText);
 
         final int size = classifications.length;
-        TextClassifierImplNative.ClassificationResult highestScoringResult = null;
+        AnnotatorModel.ClassificationResult highestScoringResult = null;
         float highestScore = Float.MIN_VALUE;
         for (int i = 0; i < size; i++) {
             builder.setEntityType(classifications[i].getCollection(),
@@ -486,9 +488,9 @@
             try {
                 final ParcelFileDescriptor modelFd = ParcelFileDescriptor.open(
                         file, ParcelFileDescriptor.MODE_READ_ONLY);
-                final int version = TextClassifierImplNative.getVersion(modelFd.getFd());
+                final int version = AnnotatorModel.getVersion(modelFd.getFd());
                 final String supportedLocalesStr =
-                        TextClassifierImplNative.getLocales(modelFd.getFd());
+                        AnnotatorModel.getLocales(modelFd.getFd());
                 if (supportedLocalesStr.isEmpty()) {
                     Log.d(DEFAULT_LOG_TAG, "Ignoring " + file.getAbsolutePath());
                     return null;
@@ -676,7 +678,7 @@
         public static List<LabeledIntent> create(
                 Context context,
                 @Nullable Instant referenceTime,
-                TextClassifierImplNative.ClassificationResult classification,
+                AnnotatorModel.ClassificationResult classification,
                 String text) {
             final String type = classification.getCollection().trim().toLowerCase(Locale.ENGLISH);
             text = text.trim();
diff --git a/core/java/android/view/textclassifier/TextClassifierImplNative.java b/core/java/android/view/textclassifier/TextClassifierImplNative.java
deleted file mode 100644
index 3d4c8f2..0000000
--- a/core/java/android/view/textclassifier/TextClassifierImplNative.java
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view.textclassifier;
-
-import android.content.res.AssetFileDescriptor;
-
-/**
- * Java wrapper for TextClassifier native library interface. This library is used for detecting
- * entities in text.
- */
-final class TextClassifierImplNative {
-
-    static {
-        System.loadLibrary("textclassifier");
-    }
-
-    private final long mModelPtr;
-
-    /**
-     * Creates a new instance of TextClassifierImplNative, using the provided model image, given as
-     * a file descriptor.
-     */
-    TextClassifierImplNative(int fd) {
-        mModelPtr = nativeNew(fd);
-        if (mModelPtr == 0L) {
-            throw new IllegalArgumentException("Couldn't initialize TC from file descriptor.");
-        }
-    }
-
-    /**
-     * Creates a new instance of TextClassifierImplNative, using the provided model image, given as
-     * a file path.
-     */
-    TextClassifierImplNative(String path) {
-        mModelPtr = nativeNewFromPath(path);
-        if (mModelPtr == 0L) {
-            throw new IllegalArgumentException("Couldn't initialize TC from given file.");
-        }
-    }
-
-    /**
-     * Creates a new instance of TextClassifierImplNative, using the provided model image, given as
-     * an AssetFileDescriptor.
-     */
-    TextClassifierImplNative(AssetFileDescriptor afd) {
-        mModelPtr = nativeNewFromAssetFileDescriptor(afd, afd.getStartOffset(), afd.getLength());
-        if (mModelPtr == 0L) {
-            throw new IllegalArgumentException(
-                    "Couldn't initialize TC from given AssetFileDescriptor");
-        }
-    }
-
-    /**
-     * Given a string context and current selection, computes the SmartSelection suggestion.
-     *
-     * <p>The begin and end are character indices into the context UTF8 string. selectionBegin is
-     * the character index where the selection begins, and selectionEnd is the index of one
-     * character past the selection span.
-     *
-     * <p>The return value is an array of two ints: suggested selection beginning and end, with the
-     * same semantics as the input selectionBeginning and selectionEnd.
-     */
-    public int[] suggestSelection(
-            String context, int selectionBegin, int selectionEnd, SelectionOptions options) {
-        return nativeSuggestSelection(mModelPtr, context, selectionBegin, selectionEnd, options);
-    }
-
-    /**
-     * Given a string context and current selection, classifies the type of the selected text.
-     *
-     * <p>The begin and end params are character indices in the context string.
-     *
-     * <p>Returns an array of ClassificationResult objects with the probability scores for different
-     * collections.
-     */
-    public ClassificationResult[] classifyText(
-            String context, int selectionBegin, int selectionEnd, ClassificationOptions options) {
-        return nativeClassifyText(mModelPtr, context, selectionBegin, selectionEnd, options);
-    }
-
-    /**
-     * Annotates given input text. The annotations should cover the whole input context except for
-     * whitespaces, and are sorted by their position in the context string.
-     */
-    public AnnotatedSpan[] annotate(String text, AnnotationOptions options) {
-        return nativeAnnotate(mModelPtr, text, options);
-    }
-
-    /** Frees up the allocated memory. */
-    public void close() {
-        nativeClose(mModelPtr);
-    }
-
-    /** Returns a comma separated list of locales supported by the model as BCP 47 tags. */
-    public static String getLocales(int fd) {
-        return nativeGetLocales(fd);
-    }
-
-    /** Returns the version of the model. */
-    public static int getVersion(int fd) {
-        return nativeGetVersion(fd);
-    }
-
-    /** Represents a datetime parsing result from classifyText calls. */
-    public static final class DatetimeResult {
-        static final int GRANULARITY_YEAR = 0;
-        static final int GRANULARITY_MONTH = 1;
-        static final int GRANULARITY_WEEK = 2;
-        static final int GRANULARITY_DAY = 3;
-        static final int GRANULARITY_HOUR = 4;
-        static final int GRANULARITY_MINUTE = 5;
-        static final int GRANULARITY_SECOND = 6;
-
-        private final long mTimeMsUtc;
-        private final int mGranularity;
-
-        DatetimeResult(long timeMsUtc, int granularity) {
-            mGranularity = granularity;
-            mTimeMsUtc = timeMsUtc;
-        }
-
-        public long getTimeMsUtc() {
-            return mTimeMsUtc;
-        }
-
-        public int getGranularity() {
-            return mGranularity;
-        }
-    }
-
-    /** Represents a result of classifyText method call. */
-    public static final class ClassificationResult {
-        private final String mCollection;
-        private final float mScore;
-        private final DatetimeResult mDatetimeResult;
-
-        ClassificationResult(
-                String collection, float score, DatetimeResult datetimeResult) {
-            mCollection = collection;
-            mScore = score;
-            mDatetimeResult = datetimeResult;
-        }
-
-        public String getCollection() {
-            if (mCollection.equals(TextClassifier.TYPE_DATE) && mDatetimeResult != null) {
-                switch (mDatetimeResult.getGranularity()) {
-                    case DatetimeResult.GRANULARITY_HOUR:
-                        // fall through
-                    case DatetimeResult.GRANULARITY_MINUTE:
-                        // fall through
-                    case DatetimeResult.GRANULARITY_SECOND:
-                        return TextClassifier.TYPE_DATE_TIME;
-                    default:
-                        return TextClassifier.TYPE_DATE;
-                }
-            }
-            return mCollection;
-        }
-
-        public float getScore() {
-            return mScore;
-        }
-
-        public DatetimeResult getDatetimeResult() {
-            return mDatetimeResult;
-        }
-    }
-
-    /** Represents a result of Annotate call. */
-    public static final class AnnotatedSpan {
-        private final int mStartIndex;
-        private final int mEndIndex;
-        private final ClassificationResult[] mClassification;
-
-        AnnotatedSpan(
-                int startIndex, int endIndex, ClassificationResult[] classification) {
-            mStartIndex = startIndex;
-            mEndIndex = endIndex;
-            mClassification = classification;
-        }
-
-        public int getStartIndex() {
-            return mStartIndex;
-        }
-
-        public int getEndIndex() {
-            return mEndIndex;
-        }
-
-        public ClassificationResult[] getClassification() {
-            return mClassification;
-        }
-    }
-
-    /** Represents options for the suggestSelection call. */
-    public static final class SelectionOptions {
-        private final String mLocales;
-
-        SelectionOptions(String locales) {
-            mLocales = locales;
-        }
-
-        public String getLocales() {
-            return mLocales;
-        }
-    }
-
-    /** Represents options for the classifyText call. */
-    public static final class ClassificationOptions {
-        private final long mReferenceTimeMsUtc;
-        private final String mReferenceTimezone;
-        private final String mLocales;
-
-        ClassificationOptions(long referenceTimeMsUtc, String referenceTimezone, String locale) {
-            mReferenceTimeMsUtc = referenceTimeMsUtc;
-            mReferenceTimezone = referenceTimezone;
-            mLocales = locale;
-        }
-
-        public long getReferenceTimeMsUtc() {
-            return mReferenceTimeMsUtc;
-        }
-
-        public String getReferenceTimezone() {
-            return mReferenceTimezone;
-        }
-
-        public String getLocale() {
-            return mLocales;
-        }
-    }
-
-    /** Represents options for the Annotate call. */
-    public static final class AnnotationOptions {
-        private final long mReferenceTimeMsUtc;
-        private final String mReferenceTimezone;
-        private final String mLocales;
-
-        AnnotationOptions(long referenceTimeMsUtc, String referenceTimezone, String locale) {
-            mReferenceTimeMsUtc = referenceTimeMsUtc;
-            mReferenceTimezone = referenceTimezone;
-            mLocales = locale;
-        }
-
-        public long getReferenceTimeMsUtc() {
-            return mReferenceTimeMsUtc;
-        }
-
-        public String getReferenceTimezone() {
-            return mReferenceTimezone;
-        }
-
-        public String getLocale() {
-            return mLocales;
-        }
-    }
-
-    private static native long nativeNew(int fd);
-
-    private static native long nativeNewFromPath(String path);
-
-    private static native long nativeNewFromAssetFileDescriptor(
-            AssetFileDescriptor afd, long offset, long size);
-
-    private static native int[] nativeSuggestSelection(
-            long context,
-            String text,
-            int selectionBegin,
-            int selectionEnd,
-            SelectionOptions options);
-
-    private static native ClassificationResult[] nativeClassifyText(
-            long context,
-            String text,
-            int selectionBegin,
-            int selectionEnd,
-            ClassificationOptions options);
-
-    private static native AnnotatedSpan[] nativeAnnotate(
-            long context, String text, AnnotationOptions options);
-
-    private static native void nativeClose(long context);
-
-    private static native String nativeGetLocales(int fd);
-
-    private static native int nativeGetVersion(int fd);
-}
diff --git a/core/java/android/view/textservice/SpellCheckerSubtype.java b/core/java/android/view/textservice/SpellCheckerSubtype.java
index 026610e..d904d467 100644
--- a/core/java/android/view/textservice/SpellCheckerSubtype.java
+++ b/core/java/android/view/textservice/SpellCheckerSubtype.java
@@ -25,7 +25,7 @@
 import android.text.TextUtils;
 import android.util.Slog;
 
-import com.android.internal.inputmethod.InputMethodUtils;
+import com.android.internal.inputmethod.SubtypeLocaleUtils;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -228,7 +228,7 @@
         if (!TextUtils.isEmpty(mSubtypeLanguageTag)) {
             return Locale.forLanguageTag(mSubtypeLanguageTag);
         }
-        return InputMethodUtils.constructLocaleFromString(mSubtypeLocale);
+        return SubtypeLocaleUtils.constructLocaleFromString(mSubtypeLocale);
     }
 
     /**
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index ae6a2fd..23d1237 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -25,6 +25,13 @@
  * Cookies are manipulated according to RFC2109.
  */
 public abstract class CookieManager {
+    /**
+     * @deprecated This class should not be constructed by applications, use {@link #getInstance}
+     * instead to fetch the singleton instance.
+     */
+    // TODO(ntfschr): mark this as @SystemApi after a year.
+    @Deprecated
+    public CookieManager() {}
 
     @Override
     protected Object clone() throws CloneNotSupportedException {
diff --git a/core/java/android/webkit/RenderProcessGoneDetail.java b/core/java/android/webkit/RenderProcessGoneDetail.java
index 0843e26..9beeaa5 100644
--- a/core/java/android/webkit/RenderProcessGoneDetail.java
+++ b/core/java/android/webkit/RenderProcessGoneDetail.java
@@ -22,6 +22,13 @@
  **/
 public abstract class RenderProcessGoneDetail {
     /**
+     * @deprecated This class should not be constructed by applications.
+     */
+    // TODO(ntfschr): mark this as @SystemApi after a year.
+    @Deprecated
+    public RenderProcessGoneDetail() {}
+
+    /**
      * Indicates whether the render process was observed to crash, or whether
      * it was killed by the system.
      *
diff --git a/core/java/android/webkit/SafeBrowsingResponse.java b/core/java/android/webkit/SafeBrowsingResponse.java
index 1d3a617..ca33a0c 100644
--- a/core/java/android/webkit/SafeBrowsingResponse.java
+++ b/core/java/android/webkit/SafeBrowsingResponse.java
@@ -27,6 +27,12 @@
  * {@link android.webkit.WebView#getSafeBrowsingPrivacyPolicyUrl()}.
  */
 public abstract class SafeBrowsingResponse {
+    /**
+     * @deprecated This class should not be constructed by applications.
+     */
+    // TODO(ntfschr): mark this as @SystemApi after a year.
+    @Deprecated
+    public SafeBrowsingResponse() {}
 
     /**
      * Display the default interstitial.
@@ -36,14 +42,14 @@
     public abstract void showInterstitial(boolean allowReporting);
 
     /**
-     * Act as if the user clicked "visit this unsafe site."
+     * Act as if the user clicked the "visit this unsafe site" button.
      *
      * @param report {@code true} to enable Safe Browsing reporting.
      */
     public abstract void proceed(boolean report);
 
     /**
-     * Act as if the user clicked "back to safety."
+     * Act as if the user clicked the "back to safety" button.
      *
      * @param report {@code true} to enable Safe Browsing reporting.
      */
diff --git a/core/java/android/webkit/ServiceWorkerController.java b/core/java/android/webkit/ServiceWorkerController.java
index 3517c74..d7e0715 100644
--- a/core/java/android/webkit/ServiceWorkerController.java
+++ b/core/java/android/webkit/ServiceWorkerController.java
@@ -38,6 +38,14 @@
 public abstract class ServiceWorkerController {
 
     /**
+     * @deprecated This class should not be constructed by applications, use {@link #getInstance()}
+     * instead to fetch the singleton instance.
+     */
+    // TODO(ntfschr): mark this as @SystemApi after a year.
+    @Deprecated
+    public ServiceWorkerController() {}
+
+    /**
      * Returns the default ServiceWorkerController instance. At present there is
      * only one ServiceWorkerController instance for all WebView instances,
      * however this restriction may be relaxed in the future.
diff --git a/core/java/android/webkit/TracingController.java b/core/java/android/webkit/TracingController.java
index 05c0304..9908182 100644
--- a/core/java/android/webkit/TracingController.java
+++ b/core/java/android/webkit/TracingController.java
@@ -36,13 +36,20 @@
  * <pre class="prettyprint">
  * TracingController tracingController = TracingController.getInstance();
  * tracingController.start(new TracingConfig.Builder()
- *                  .addCategories(CATEGORIES_WEB_DEVELOPER).build());
+ *                  .addCategories(TracingConfig.CATEGORIES_WEB_DEVELOPER).build());
  * ...
  * tracingController.stop(new FileOutputStream("trace.json"),
  *                        Executors.newSingleThreadExecutor());
  * </pre></p>
  */
 public abstract class TracingController {
+    /**
+     * @deprecated This class should not be constructed by applications, use {@link #getInstance}
+     * instead to fetch the singleton instance.
+     */
+    // TODO(ntfschr): mark this as @SystemApi after a year.
+    @Deprecated
+    public TracingController() {}
 
     /**
      * Returns the default TracingController instance. At present there is
diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java
index f6166c5..f346c60 100644
--- a/core/java/android/webkit/WebViewDatabase.java
+++ b/core/java/android/webkit/WebViewDatabase.java
@@ -31,6 +31,14 @@
  */
 public abstract class WebViewDatabase {
     /**
+     * @deprecated This class should not be constructed by applications, use {@link
+     * #getInstance(Context)} instead to fetch the singleton instance.
+     */
+    // TODO(ntfschr): mark this as @SystemApi after a year.
+    @Deprecated
+    public WebViewDatabase() {}
+
+    /**
      * @hide Since API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}
      */
     protected static final String LOGTAG = "webviewdatabase";
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index dd6c923..f3fe16e 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -682,7 +682,7 @@
 
     /**
      * Sets the currently selected item. To support accessibility subclasses that
-     * override this method must invoke the overriden super method first.
+     * override this method must invoke the overridden super method first.
      *
      * @param position Index (starting at 0) of the data item to be selected.
      */
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 71d13a9..7d6564f 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -24,6 +24,7 @@
 import android.database.DataSetObserver;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.text.Editable;
 import android.text.Selection;
 import android.text.TextUtils;
@@ -533,7 +534,7 @@
      *
      * @hide Pending API council approval
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public void setDropDownAnimationStyle(int animationStyle) {
         mPopup.setAnimationStyle(animationStyle);
     }
@@ -1157,7 +1158,7 @@
      * <p>Closes the drop down if present on screen.</p>
      */
     public void dismissDropDown() {
-        InputMethodManager imm = InputMethodManager.peekInstance();
+        InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
         if (imm != null) {
             imm.displayCompletions(this, null);
         }
@@ -1246,7 +1247,7 @@
     private void buildImeCompletions() {
         final ListAdapter adapter = mAdapter;
         if (adapter != null) {
-            InputMethodManager imm = InputMethodManager.peekInstance();
+            InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
             if (imm != null) {
                 final int count = Math.min(adapter.getCount(), 20);
                 CompletionInfo[] completions = new CompletionInfo[count];
diff --git a/core/java/android/widget/CursorAdapter.java b/core/java/android/widget/CursorAdapter.java
index cc8b550..e250f63 100644
--- a/core/java/android/widget/CursorAdapter.java
+++ b/core/java/android/widget/CursorAdapter.java
@@ -365,7 +365,7 @@
      * closed.
      *
      * @param newCursor The new cursor to be used.
-     * @return Returns the previously set Cursor, or null if there wasa not one.
+     * @return Returns the previously set Cursor, or null if there was not one.
      * If the given new Cursor is the same instance is the previously set
      * Cursor, null is also returned.
      */
diff --git a/core/java/android/widget/DatePickerSpinnerDelegate.java b/core/java/android/widget/DatePickerSpinnerDelegate.java
index f88a4e2..5f15110 100644
--- a/core/java/android/widget/DatePickerSpinnerDelegate.java
+++ b/core/java/android/widget/DatePickerSpinnerDelegate.java
@@ -639,7 +639,7 @@
         // changed the value via the IME and there is a next input the IME will
         // be shown, otherwise the user chose another means of changing the
         // value and having the IME up makes no sense.
-        InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
+        InputMethodManager inputMethodManager = mContext.getSystemService(InputMethodManager.class);
         if (inputMethodManager != null) {
             if (inputMethodManager.isActive(mYearSpinnerInput)) {
                 mYearSpinnerInput.clearFocus();
diff --git a/core/java/android/widget/DigitalClock.java b/core/java/android/widget/DigitalClock.java
index c503ef2..8ebf303 100644
--- a/core/java/android/widget/DigitalClock.java
+++ b/core/java/android/widget/DigitalClock.java
@@ -27,7 +27,7 @@
 import java.util.Calendar;
 
 /**
- * Like AnalogClock, but digital.  Shows seconds.
+ * Like AnalogClock, but digital.
  *
  * @deprecated It is recommended you use {@link TextClock} instead.
  */
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 4428598..9d74c98 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -388,7 +388,8 @@
                 com.android.internal.R.bool.config_enableHapticTextHandle);
 
         if (FLAG_USE_MAGNIFIER) {
-            mMagnifierAnimator = new MagnifierMotionAnimator(new Magnifier(mTextView));
+            final Magnifier magnifier = new Magnifier.Builder(mTextView).build();
+            mMagnifierAnimator = new MagnifierMotionAnimator(magnifier);
         }
     }
 
@@ -1539,6 +1540,10 @@
         }
     }
 
+    private InputMethodManager getInputMethodManager() {
+        return mTextView.getContext().getSystemService(InputMethodManager.class);
+    }
+
     public void beginBatchEdit() {
         mInBatchEditControllers = true;
         final InputMethodState ims = mInputMethodState;
@@ -1707,7 +1712,7 @@
         if (req == null) {
             return false;
         }
-        final InputMethodManager imm = InputMethodManager.peekInstance();
+        final InputMethodManager imm = getInputMethodManager();
         if (imm == null) {
             return false;
         }
@@ -1742,7 +1747,7 @@
 
     private void sendUpdateSelection() {
         if (null != mInputMethodState && mInputMethodState.mBatchEditNesting <= 0) {
-            final InputMethodManager imm = InputMethodManager.peekInstance();
+            final InputMethodManager imm = getInputMethodManager();
             if (null != imm) {
                 final int selectionStart = mTextView.getSelectionStart();
                 final int selectionEnd = mTextView.getSelectionEnd();
@@ -1768,7 +1773,7 @@
 
         final InputMethodState ims = mInputMethodState;
         if (ims != null && ims.mBatchEditNesting == 0) {
-            InputMethodManager imm = InputMethodManager.peekInstance();
+            InputMethodManager imm = getInputMethodManager();
             if (imm != null) {
                 if (imm.isActive(mTextView)) {
                     if (ims.mContentChanged || ims.mSelectionModeChanged) {
@@ -2245,7 +2250,7 @@
                 && mTextView.isTextEditable() && !mTextView.isTextSelectable()
                 && mShowSoftInputOnFocus) {
             // Show the IME to be able to replace text, except when selecting non editable text.
-            final InputMethodManager imm = InputMethodManager.peekInstance();
+            final InputMethodManager imm = getInputMethodManager();
             if (imm != null) {
                 imm.showSoftInput(mTextView, 0, null);
             }
@@ -2255,7 +2260,7 @@
 
     private boolean extractedTextModeWillBeStarted() {
         if (!(mTextView.isInExtractedMode())) {
-            final InputMethodManager imm = InputMethodManager.peekInstance();
+            final InputMethodManager imm = getInputMethodManager();
             return  imm != null && imm.isFullscreenMode();
         }
         return false;
@@ -4272,7 +4277,7 @@
             if (ims == null || ims.mBatchEditNesting > 0) {
                 return;
             }
-            final InputMethodManager imm = InputMethodManager.peekInstance();
+            final InputMethodManager imm = getInputMethodManager();
             if (null == imm) {
                 return;
             }
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 452e903..f2e478d 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -653,7 +653,7 @@
     }
 
     /**
-     * <p>Returns the view at the specified index. This method can be overriden
+     * <p>Returns the view at the specified index. This method can be overridden
      * to take into account virtual children. Refer to
      * {@link android.widget.TableLayout} and {@link android.widget.TableRow}
      * for an example.</p>
@@ -1527,7 +1527,7 @@
 
     /**
      * <p>Measure the child according to the parent's measure specs. This
-     * method should be overriden by subclasses to force the sizing of
+     * method should be overridden by subclasses to force the sizing of
      * children. This method is called by {@link #measureVertical(int, int)} and
      * {@link #measureHorizontal(int, int)}.</p>
      *
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index 8e2786d..16ddd0f 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -119,8 +119,9 @@
      *
      * @param view the view for which this magnifier is attached
      *
-     * @see Builder
+     * @deprecated Please use {@link Builder} instead
      */
+    @Deprecated
     public Magnifier(@NonNull View view) {
         this(new Builder(view));
     }
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index b6ed22c..a28cc40 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -1293,7 +1293,8 @@
      * Shows the soft input for its input text.
      */
     private void showSoftInput() {
-        InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
+        InputMethodManager inputMethodManager =
+                getContext().getSystemService(InputMethodManager.class);
         if (inputMethodManager != null) {
             if (mHasSelectorWheel) {
                 mInputText.setVisibility(View.VISIBLE);
@@ -1307,7 +1308,8 @@
      * Hides the soft input if it is active for the input text.
      */
     private void hideSoftInput() {
-        InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
+        InputMethodManager inputMethodManager =
+                getContext().getSystemService(InputMethodManager.class);
         if (inputMethodManager != null && inputMethodManager.isActive(mInputText)) {
             inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
         }
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 5b5950d..10e1dfb 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -36,6 +36,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -1292,7 +1293,7 @@
         mSearchSrcTextView.dismissDropDown();
     }
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private void onCloseClicked() {
         CharSequence text = mSearchSrcTextView.getText();
         if (TextUtils.isEmpty(text)) {
@@ -1590,7 +1591,7 @@
     /**
      * Sets the text in the query box, without updating the suggestions.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private void setQuery(CharSequence query) {
         mSearchSrcTextView.setText(query, true);
         // Move the cursor to the end
diff --git a/core/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java
index 9a24061..c78f4ac 100644
--- a/core/java/android/widget/ShareActionProvider.java
+++ b/core/java/android/widget/ShareActionProvider.java
@@ -268,7 +268,7 @@
      * Intent shareIntent = new Intent(Intent.ACTION_SEND);
      * shareIntent.setType("image/*");
      * Uri uri = Uri.fromFile(new File(getFilesDir(), "foo.jpg"));
-     * shareIntent.putExtra(Intent.EXTRA_STREAM, uri));</pre>
+     * shareIntent.putExtra(Intent.EXTRA_STREAM, uri);</pre>
      *
      * @param shareIntent The share intent.
      *
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index d913273..f95b3ce 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -321,6 +321,12 @@
  * @attr ref android.R.styleable#TextView_autoSizeMaxTextSize
  * @attr ref android.R.styleable#TextView_autoSizeStepGranularity
  * @attr ref android.R.styleable#TextView_autoSizePresetSizes
+ * @attr ref android.R.styleable#TextView_textCursorDrawable
+ * @attr ref android.R.styleable#TextView_textSelectHandle
+ * @attr ref android.R.styleable#TextView_textSelectHandleLeft
+ * @attr ref android.R.styleable#TextView_textSelectHandleRight
+ * @attr ref android.R.styleable#TextView_allowUndo
+ * @attr ref android.R.styleable#TextView_enabled
  */
 @RemoteView
 public class TextView extends View implements ViewTreeObserver.OnPreDrawListener {
@@ -2156,7 +2162,7 @@
 
         if (!enabled) {
             // Hide the soft input if the currently active TextView is disabled
-            InputMethodManager imm = InputMethodManager.peekInstance();
+            InputMethodManager imm = getInputMethodManager();
             if (imm != null && imm.isActive(this)) {
                 imm.hideSoftInputFromWindow(getWindowToken(), 0);
             }
@@ -2166,7 +2172,7 @@
 
         if (enabled) {
             // Make sure IME is updated with current editor info.
-            InputMethodManager imm = InputMethodManager.peekInstance();
+            InputMethodManager imm = getInputMethodManager();
             if (imm != null) imm.restartInput(this);
         }
 
@@ -2392,7 +2398,7 @@
             if (mEditor != null) mEditor.mInputType = EditorInfo.TYPE_NULL;
         }
 
-        InputMethodManager imm = InputMethodManager.peekInstance();
+        InputMethodManager imm = getInputMethodManager();
         if (imm != null) imm.restartInput(this);
     }
 
@@ -3609,7 +3615,7 @@
     /**
      * Read the Text Appearance attributes from a given TypedArray and set its values to the given
      * set. If the TypedArray contains a value that was already set in the given attributes, that
-     * will be overriden.
+     * will be overridden.
      *
      * @param context The Context to be used
      * @param appearance The TypedArray to read properties from
@@ -5769,7 +5775,7 @@
             Editable t = mEditableFactory.newEditable(text);
             text = t;
             setFilters(t, mFilters);
-            InputMethodManager imm = InputMethodManager.peekInstance();
+            InputMethodManager imm = getInputMethodManager();
             if (imm != null) imm.restartInput(this);
         } else if (precomputed != null) {
             if (mTextDir == null) {
@@ -6148,7 +6154,7 @@
             setTextInternal(removeSuggestionSpans(mText));
         }
 
-        InputMethodManager imm = InputMethodManager.peekInstance();
+        InputMethodManager imm = getInputMethodManager();
         if (imm != null) imm.restartInput(this);
     }
 
@@ -6436,7 +6442,7 @@
                 return;
 
             } else if (actionCode == EditorInfo.IME_ACTION_DONE) {
-                InputMethodManager imm = InputMethodManager.peekInstance();
+                InputMethodManager imm = getInputMethodManager();
                 if (imm != null && imm.isActive(this)) {
                     imm.hideSoftInputFromWindow(getWindowToken(), 0);
                 }
@@ -7902,7 +7908,7 @@
                     if (!hasOnClickListeners()) {
                         if (mMovement != null && mText instanceof Editable
                                 && mLayout != null && onCheckIsTextEditor()) {
-                            InputMethodManager imm = InputMethodManager.peekInstance();
+                            InputMethodManager imm = getInputMethodManager();
                             viewClicked(imm);
                             if (imm != null && getShowSoftInputOnFocus()) {
                                 imm.showSoftInput(this, 0);
@@ -7956,7 +7962,7 @@
                                     & KeyEvent.FLAG_EDITOR_ACTION) != 0) {
                                 // No target for next focus, but make sure the IME
                                 // if this came from it.
-                                InputMethodManager imm = InputMethodManager.peekInstance();
+                                InputMethodManager imm = getInputMethodManager();
                                 if (imm != null && imm.isActive(this)) {
                                     imm.hideSoftInputFromWindow(getWindowToken(), 0);
                                 }
@@ -10260,7 +10266,7 @@
 
             if (touchIsFinished && (isTextEditable() || textIsSelectable)) {
                 // Show the IME, except when selecting in read-only text.
-                final InputMethodManager imm = InputMethodManager.peekInstance();
+                final InputMethodManager imm = getInputMethodManager();
                 viewClicked(imm);
                 if (isTextEditable() && mEditor.mShowSoftInputOnFocus && imm != null) {
                     imm.showSoftInput(this, 0);
@@ -11299,7 +11305,7 @@
         // Show the IME, except when selecting in read-only text.
         if ((mMovement != null || onCheckIsTextEditor()) && hasSpannableText() && mLayout != null
                 && (isTextEditable() || isTextSelectable()) && isFocused()) {
-            final InputMethodManager imm = InputMethodManager.peekInstance();
+            final InputMethodManager imm = getInputMethodManager();
             viewClicked(imm);
             if (!isTextSelectable() && mEditor.mShowSoftInputOnFocus && imm != null) {
                 handled |= imm.showSoftInput(this, 0);
@@ -11367,13 +11373,17 @@
         sendAccessibilityEventUnchecked(event);
     }
 
+    private InputMethodManager getInputMethodManager() {
+        return getContext().getSystemService(InputMethodManager.class);
+    }
+
     /**
      * Returns whether this text view is a current input method target.  The
      * default implementation just checks with {@link InputMethodManager}.
      * @return True if the TextView is a current input method target; false otherwise.
      */
     public boolean isInputMethodTarget() {
-        InputMethodManager imm = InputMethodManager.peekInstance();
+        InputMethodManager imm = getInputMethodManager();
         return imm != null && imm.isActive(this);
     }
 
@@ -12491,11 +12501,11 @@
                     advancesIndex);
         }
 
-        public int getTextRunCursor(int contextStart, int contextEnd, int dir,
+        public int getTextRunCursor(int contextStart, int contextEnd, boolean isRtl,
                 int offset, int cursorOpt, Paint p) {
             int contextCount = contextEnd - contextStart;
             return p.getTextRunCursor(mChars, contextStart + mStart,
-                    contextCount, dir, offset + mStart, cursorOpt);
+                    contextCount, isRtl, offset + mStart, cursorOpt);
         }
     }
 
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 77670b3..6a3a8f0 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -269,7 +269,7 @@
             mRadialTimePickerModeButton.setContentDescription(
                     mTextInputPickerModeEnabledDescription);
             updateTextInputPicker();
-            InputMethodManager imm = InputMethodManager.peekInstance();
+            InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
             if (imm != null) {
                 imm.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
             }
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index cc79b9c..83c86d5 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -471,7 +471,7 @@
         // changed the value via the IME and there is a next input the IME will
         // be shown, otherwise the user chose another means of changing the
         // value and having the IME up makes no sense.
-        InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
+        InputMethodManager inputMethodManager = mContext.getSystemService(InputMethodManager.class);
         if (inputMethodManager != null) {
             if (inputMethodManager.isActive(mHourSpinnerInput)) {
                 mHourSpinnerInput.clearFocus();
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 3fbc819..10cf702 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -27,6 +27,7 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.PixelFormat;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -443,7 +444,7 @@
          * schedule handleShow into the right thread
          */
         @Override
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public void show(IBinder windowToken) {
             if (localLOGV) Log.v(TAG, "SHOW: " + this);
             mHandler.obtainMessage(SHOW, windowToken).sendToTarget();
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index 1bbd7e8..adb7f2f 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -29,6 +29,7 @@
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.Layout;
@@ -137,7 +138,7 @@
     @UnsupportedAppUsage
     private TextView mTitleTextView;
     private TextView mSubtitleTextView;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private ImageButton mNavButtonView;
     private ImageView mLogoView;
 
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index 14881eb..8b45d99 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -38,6 +38,7 @@
 import android.media.TtmlRenderer;
 import android.media.WebVttRenderer;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Looper;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -85,7 +86,7 @@
 
     // all possible internal states
     private static final int STATE_ERROR = -1;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private static final int STATE_IDLE = 0;
     private static final int STATE_PREPARING = 1;
     private static final int STATE_PREPARED = 2;
diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
index 90712fd..e83e79b 100644
--- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
+++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
@@ -16,6 +16,10 @@
 
 package com.android.internal.accessibility;
 
+import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
+
+import static com.android.internal.util.ArrayUtils.convertToLongArray;
+
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.app.ActivityManager;
 import android.app.ActivityThread;
@@ -34,23 +38,23 @@
 import android.os.UserHandle;
 import android.os.Vibrator;
 import android.provider.Settings;
+import android.speech.tts.TextToSpeech;
+import android.speech.tts.Voice;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Slog;
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
-
 import android.widget.Toast;
+
 import com.android.internal.R;
+import com.android.internal.util.function.pooled.PooledLambda;
 
 import java.util.Collections;
+import java.util.Locale;
 import java.util.Map;
 
-import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
-
-import static com.android.internal.util.ArrayUtils.convertToLongArray;
-
 /**
  * Class to help manage the accessibility shortcut
  */
@@ -70,6 +74,7 @@
     private static Map<ComponentName, ToggleableFrameworkFeatureInfo> sFrameworkShortcutFeaturesMap;
 
     private final Context mContext;
+    private final Handler mHandler;
     private AlertDialog mAlertDialog;
     private boolean mIsShortcutEnabled;
     private boolean mEnabledOnLockScreen;
@@ -123,6 +128,7 @@
 
     public AccessibilityShortcutController(Context context, Handler handler, int initialUserId) {
         mContext = context;
+        mHandler = handler;
         mUserId = initialUserId;
 
         // Keep track of state of shortcut settings
@@ -189,22 +195,6 @@
         final int userId = ActivityManager.getCurrentUser();
         final int dialogAlreadyShown = Settings.Secure.getIntForUser(
                 cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0, userId);
-        // Use USAGE_ASSISTANCE_ACCESSIBILITY for TVs to ensure that TVs play the ringtone as they
-        // have less ways of providing feedback like vibration.
-        final int audioAttributesUsage = hasFeatureLeanback()
-                ? AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY
-                : AudioAttributes.USAGE_NOTIFICATION_EVENT;
-
-        // Play a notification tone
-        final Ringtone tone =
-                RingtoneManager.getRingtone(mContext, Settings.System.DEFAULT_NOTIFICATION_URI);
-        if (tone != null) {
-            tone.setAudioAttributes(new AudioAttributes.Builder()
-                .setUsage(audioAttributesUsage)
-                .build());
-            tone.play();
-        }
-
         // Play a notification vibration
         Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
         if ((vibrator != null) && vibrator.hasVibrator()) {
@@ -223,6 +213,9 @@
             if (mAlertDialog == null) {
                 return;
             }
+            if (!performTtsPrompt(mAlertDialog)) {
+                playNotificationTone();
+            }
             Window w = mAlertDialog.getWindow();
             WindowManager.LayoutParams attr = w.getAttributes();
             attr.type = TYPE_KEYGUARD_DIALOG;
@@ -231,6 +224,7 @@
             Settings.Secure.putIntForUser(
                     cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 1, userId);
         } else {
+            playNotificationTone();
             if (mAlertDialog != null) {
                 mAlertDialog.dismiss();
                 mAlertDialog = null;
@@ -344,6 +338,102 @@
         return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
     }
 
+    private void playNotificationTone() {
+        // Use USAGE_ASSISTANCE_ACCESSIBILITY for TVs to ensure that TVs play the ringtone as they
+        // have less ways of providing feedback like vibration.
+        final int audioAttributesUsage = hasFeatureLeanback()
+                ? AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY
+                : AudioAttributes.USAGE_NOTIFICATION_EVENT;
+
+        // Play a notification tone
+        final Ringtone tone = mFrameworkObjectProvider.getRingtone(mContext,
+                Settings.System.DEFAULT_NOTIFICATION_URI);
+        if (tone != null) {
+            tone.setAudioAttributes(new AudioAttributes.Builder()
+                    .setUsage(audioAttributesUsage)
+                    .build());
+            tone.play();
+        }
+    }
+
+    private boolean performTtsPrompt(AlertDialog alertDialog) {
+        final AccessibilityServiceInfo serviceInfo = getInfoForTargetService();
+        if (serviceInfo == null) {
+            return false;
+        }
+        if ((serviceInfo.flags & AccessibilityServiceInfo
+                .FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK) == 0) {
+            return false;
+        }
+        final TtsPrompt tts = new TtsPrompt();
+        alertDialog.setOnDismissListener(dialog -> tts.dismiss());
+        return true;
+    }
+
+    /**
+     * Class to wrap TextToSpeech for shortcut dialog spoken feedback.
+     */
+    private class TtsPrompt implements TextToSpeech.OnInitListener {
+        private final CharSequence mText;
+        private boolean mDismiss;
+        private TextToSpeech mTts;
+
+        TtsPrompt() {
+            mText = mContext.getString(R.string.accessibility_shortcut_spoken_feedback);
+            mTts = mFrameworkObjectProvider.getTextToSpeech(mContext, this);
+        }
+
+        /**
+         * Releases the resources used by the TextToSpeech, when dialog dismiss.
+         */
+        public void dismiss() {
+            mDismiss = true;
+            mHandler.sendMessage(PooledLambda.obtainMessage(TextToSpeech::shutdown, mTts));
+        }
+
+        @Override
+        public void onInit(int status) {
+            if (status != TextToSpeech.SUCCESS) {
+                Slog.d(TAG, "Tts init fail, status=" + Integer.toString(status));
+                playNotificationTone();
+                return;
+            }
+            mHandler.sendMessage(PooledLambda.obtainMessage(TtsPrompt::play, this));
+        }
+
+        private void play() {
+            if (mDismiss) {
+                return;
+            }
+            int status = TextToSpeech.ERROR;
+            if (setLanguage(Locale.getDefault())) {
+                status = mTts.speak(mText, TextToSpeech.QUEUE_FLUSH, null, null);
+            }
+            if (status != TextToSpeech.SUCCESS) {
+                Slog.d(TAG, "Tts play fail");
+                playNotificationTone();
+            }
+        }
+
+        /**
+         * @return false if tts language is not available
+         */
+        private boolean setLanguage(final Locale locale) {
+            int status = mTts.isLanguageAvailable(locale);
+            if (status == TextToSpeech.LANG_MISSING_DATA
+                    || status == TextToSpeech.LANG_NOT_SUPPORTED) {
+                return false;
+            }
+            mTts.setLanguage(locale);
+            Voice voice = mTts.getVoice();
+            if (voice == null || (voice.getFeatures() != null && voice.getFeatures()
+                    .contains(TextToSpeech.Engine.KEY_FEATURE_NOT_INSTALLED))) {
+                return false;
+            }
+            return true;
+        }
+    }
+
     /**
      * Immutable class to hold info about framework features that can be controlled by shortcut
      */
@@ -406,5 +496,23 @@
         public Context getSystemUiContext() {
             return ActivityThread.currentActivityThread().getSystemUiContext();
         }
+
+        /**
+         * @param ctx A context for TextToSpeech
+         * @param listener TextToSpeech initialization callback
+         * @return TextToSpeech instance
+         */
+        public TextToSpeech getTextToSpeech(Context ctx, TextToSpeech.OnInitListener listener) {
+            return new TextToSpeech(ctx, listener);
+        }
+
+        /**
+         * @param ctx context for ringtone
+         * @param uri ringtone uri
+         * @return Ringtone instance
+         */
+        public Ringtone getRingtone(Context ctx, Uri uri) {
+            return RingtoneManager.getRingtone(ctx, uri);
+        }
     }
 }
diff --git a/core/java/com/android/internal/app/AssistUtils.java b/core/java/com/android/internal/app/AssistUtils.java
index 9171959..0f8295a 100644
--- a/core/java/com/android/internal/app/AssistUtils.java
+++ b/core/java/com/android/internal/app/AssistUtils.java
@@ -16,8 +16,7 @@
 
 package com.android.internal.app;
 
-import com.android.internal.R;
-
+import android.annotation.NonNull;
 import android.app.SearchManager;
 import android.content.ComponentName;
 import android.content.Context;
@@ -32,6 +31,9 @@
 import android.provider.Settings;
 import android.util.Log;
 
+import java.util.ArrayList;
+import java.util.Set;
+
 /**
  * Utility method for dealing with the assistant aspects of
  * {@link com.android.internal.app.IVoiceInteractionManagerService IVoiceInteractionManagerService}.
@@ -62,6 +64,30 @@
         return false;
     }
 
+    /**
+     * Checks the availability of a set of voice actions for the current active voice service.
+     *
+     * @param voiceActions A set of supported voice actions to be checked.
+     * @param callback     The callback which will deliver a set of supported voice actions. If
+     *                     no voice actions are supported for the given voice action set, then null
+     *                     or empty set is provided.
+     */
+    public void getActiveServiceSupportedActions(@NonNull Set<String> voiceActions,
+            @NonNull IVoiceActionCheckCallback callback) {
+        try {
+            if (mVoiceInteractionManagerService != null) {
+                mVoiceInteractionManagerService
+                        .getActiveServiceSupportedActions(new ArrayList<>(voiceActions), callback);
+            }
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to call activeServiceSupportedActions", e);
+            try {
+                callback.onComplete(null);
+            } catch (RemoteException re) {
+            }
+        }
+    }
+
     public void launchVoiceAssistFromKeyguard() {
         try {
             if (mVoiceInteractionManagerService != null) {
@@ -157,7 +183,7 @@
             return getActiveServiceComponentName();
         }
         final SearchManager searchManager =
-            (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
+                (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
         if (searchManager == null) {
             return null;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/events/StoppedDragingEvent.java b/core/java/com/android/internal/app/IVoiceActionCheckCallback.aidl
similarity index 63%
copy from packages/SystemUI/src/com/android/systemui/stackdivider/events/StoppedDragingEvent.java
copy to core/java/com/android/internal/app/IVoiceActionCheckCallback.aidl
index c50d6d6..66ba93d 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/events/StoppedDragingEvent.java
+++ b/core/java/com/android/internal/app/IVoiceActionCheckCallback.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2018 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -11,15 +11,11 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
  */
 
-package com.android.systemui.stackdivider.events;
+package com.android.internal.app;
 
-import com.android.systemui.recents.events.EventBus;
-
-/**
- * Sent when the divider isn't draging anymore.
- */
-public class StoppedDragingEvent extends EventBus.Event {
+oneway interface IVoiceActionCheckCallback {
+    void onComplete(in List<String> voiceActions);
 }
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index ff75a8b..5088cca 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -20,6 +20,7 @@
 import android.content.Intent;
 import android.os.Bundle;
 
+import com.android.internal.app.IVoiceActionCheckCallback;
 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.app.IVoiceInteractionSessionListener;
@@ -143,4 +144,11 @@
      * Register a voice interaction listener.
      */
     void registerVoiceInteractionSessionListener(IVoiceInteractionSessionListener listener);
+
+    /**
+     * Checks the availability of a set of voice actions for the current active voice service.
+     * Returns all supported voice actions.
+     */
+    void getActiveServiceSupportedActions(in List<String> voiceActions,
+     in IVoiceActionCheckCallback callback);
 }
diff --git a/core/java/com/android/internal/app/procstats/IProcessStats.aidl b/core/java/com/android/internal/app/procstats/IProcessStats.aidl
index 44867c7..0c203ab 100644
--- a/core/java/com/android/internal/app/procstats/IProcessStats.aidl
+++ b/core/java/com/android/internal/app/procstats/IProcessStats.aidl
@@ -24,4 +24,14 @@
     byte[] getCurrentStats(out List<ParcelFileDescriptor> historic);
     ParcelFileDescriptor getStatsOverTime(long minTime);
     int getCurrentMemoryState();
+
+    /**
+     * Get stats committed after highWaterMarkMs
+     * @param highWaterMarkMs Report stats committed after this time.
+     * @param section Integer mask to indicate which sections to include in the stats.
+     * @param doAggregate Whether to aggregate the stats or keep them separated.
+     * @param List of Files of individual commits in protobuf binary or one that is merged from them.
+     */
+     long getCommittedStats(long highWaterMarkMs, int section, boolean doAggregate,
+        out List<ParcelFileDescriptor> committedStats);
 }
diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java
index f6e99ba..e7ac566 100644
--- a/core/java/com/android/internal/app/procstats/ProcessStats.java
+++ b/core/java/com/android/internal/app/procstats/ProcessStats.java
@@ -158,6 +158,25 @@
             STATE_CACHED_ACTIVITY_CLIENT, STATE_CACHED_EMPTY
     };
 
+    // Should report process stats.
+    public static final int REPORT_PROC_STATS = 0x01;
+    // Should report package process stats.
+    public static final int REPORT_PKG_PROC_STATS = 0x02;
+    // Should report package service stats.
+    public static final int REPORT_PKG_SVC_STATS = 0x04;
+    // Should report package association stats.
+    public static final int REPORT_PKG_ASC_STATS = 0x08;
+    // Should report package stats.
+    public static final int REPORT_PKG_STATS = 0x0E;
+    // Should report all stats.
+    public static final int REPORT_ALL = 0x0F;
+
+    public static final int[] OPTIONS =
+            {REPORT_PROC_STATS, REPORT_PKG_PROC_STATS, REPORT_PKG_SVC_STATS, REPORT_PKG_ASC_STATS,
+                    REPORT_PKG_STATS, REPORT_ALL};
+    public static final String[] OPTIONS_STR =
+            {"proc", "pkg-proc", "pkg-svc", "pkg-asc", "pkg-all", "all"};
+
     // Current version of the parcel format.
     private static final int PARCEL_VERSION = 34;
     // In-memory Parcel magic number, used to detect attempts to unmarshall bad data
@@ -1412,7 +1431,7 @@
     }
 
     public void dumpLocked(PrintWriter pw, String reqPackage, long now, boolean dumpSummary,
-            boolean dumpDetails, boolean dumpAll, boolean activeOnly) {
+            boolean dumpDetails, boolean dumpAll, boolean activeOnly, int section) {
         long totalTime = DumpUtils.dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
                 mStartTime, now);
         boolean sepNeeded = false;
@@ -1421,176 +1440,205 @@
             mSysMemUsage.dump(pw, "  ", ALL_SCREEN_ADJ, ALL_MEM_ADJ);
             sepNeeded = true;
         }
-        ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap = mPackages.getMap();
         boolean printedHeader = false;
-        for (int ip=0; ip<pkgMap.size(); ip++) {
-            final String pkgName = pkgMap.keyAt(ip);
-            final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
-            for (int iu=0; iu<uids.size(); iu++) {
-                final int uid = uids.keyAt(iu);
-                final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu);
-                for (int iv=0; iv<vpkgs.size(); iv++) {
-                    final long vers = vpkgs.keyAt(iv);
-                    final PackageState pkgState = vpkgs.valueAt(iv);
-                    final int NPROCS = pkgState.mProcesses.size();
-                    final int NSRVS = pkgState.mServices.size();
-                    final int NASCS = pkgState.mAssociations.size();
-                    final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName);
-                    if (!pkgMatch) {
-                        boolean procMatch = false;
-                        for (int iproc=0; iproc<NPROCS; iproc++) {
-                            ProcessState proc = pkgState.mProcesses.valueAt(iproc);
-                            if (reqPackage.equals(proc.getName())) {
-                                procMatch = true;
-                                break;
+        if ((section & REPORT_PKG_STATS) != 0) {
+            ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
+                    mPackages.getMap();
+            for (int ip = 0; ip < pkgMap.size(); ip++) {
+                final String pkgName = pkgMap.keyAt(ip);
+                final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+                for (int iu = 0; iu < uids.size(); iu++) {
+                    final int uid = uids.keyAt(iu);
+                    final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu);
+                    for (int iv = 0; iv < vpkgs.size(); iv++) {
+                        final long vers = vpkgs.keyAt(iv);
+                        final PackageState pkgState = vpkgs.valueAt(iv);
+                        final int NPROCS = pkgState.mProcesses.size();
+                        final int NSRVS = pkgState.mServices.size();
+                        final int NASCS = pkgState.mAssociations.size();
+                        final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName);
+                        if (!pkgMatch) {
+                            boolean procMatch = false;
+                            for (int iproc = 0; iproc < NPROCS; iproc++) {
+                                ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+                                if (reqPackage.equals(proc.getName())) {
+                                    procMatch = true;
+                                    break;
+                                }
                             }
-                        }
-                        if (!procMatch) {
-                            continue;
-                        }
-                    }
-                    if (NPROCS > 0 || NSRVS > 0 || NASCS > 0) {
-                        if (!printedHeader) {
-                            if (sepNeeded) pw.println();
-                            pw.println("Per-Package Stats:");
-                            printedHeader = true;
-                            sepNeeded = true;
-                        }
-                        pw.print("  * "); pw.print(pkgName); pw.print(" / ");
-                                UserHandle.formatUid(pw, uid); pw.print(" / v");
-                                pw.print(vers); pw.println(":");
-                    }
-                    if (!dumpSummary || dumpAll) {
-                        for (int iproc=0; iproc<NPROCS; iproc++) {
-                            ProcessState proc = pkgState.mProcesses.valueAt(iproc);
-                            if (!pkgMatch && !reqPackage.equals(proc.getName())) {
+                            if (!procMatch) {
                                 continue;
                             }
-                            if (activeOnly && !proc.isInUse()) {
-                                pw.print("      (Not active: ");
-                                        pw.print(pkgState.mProcesses.keyAt(iproc)); pw.println(")");
-                                continue;
+                        }
+                        if (NPROCS > 0 || NSRVS > 0 || NASCS > 0) {
+                            if (!printedHeader) {
+                                if (sepNeeded) pw.println();
+                                pw.println("Per-Package Stats:");
+                                printedHeader = true;
+                                sepNeeded = true;
                             }
-                            pw.print("      Process ");
-                            pw.print(pkgState.mProcesses.keyAt(iproc));
-                            if (proc.getCommonProcess().isMultiPackage()) {
-                                pw.print(" (multi, ");
-                            } else {
-                                pw.print(" (unique, ");
-                            }
-                            pw.print(proc.getDurationsBucketCount());
-                            pw.print(" entries)");
+                            pw.print("  * ");
+                            pw.print(pkgName);
+                            pw.print(" / ");
+                            UserHandle.formatUid(pw, uid);
+                            pw.print(" / v");
+                            pw.print(vers);
                             pw.println(":");
-                            proc.dumpProcessState(pw, "        ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
-                                    ALL_PROC_STATES, now);
-                            proc.dumpPss(pw, "        ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
-                                    ALL_PROC_STATES, now);
-                            proc.dumpInternalLocked(pw, "        ", dumpAll);
                         }
-                    } else {
-                        ArrayList<ProcessState> procs = new ArrayList<ProcessState>();
-                        for (int iproc=0; iproc<NPROCS; iproc++) {
-                            ProcessState proc = pkgState.mProcesses.valueAt(iproc);
-                            if (!pkgMatch && !reqPackage.equals(proc.getName())) {
-                                continue;
+                        if ((section & REPORT_PKG_PROC_STATS) != 0) {
+                            if (!dumpSummary || dumpAll) {
+                                for (int iproc = 0; iproc < NPROCS; iproc++) {
+                                    ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+                                    if (!pkgMatch && !reqPackage.equals(proc.getName())) {
+                                        continue;
+                                    }
+                                    if (activeOnly && !proc.isInUse()) {
+                                        pw.print("      (Not active: ");
+                                        pw.print(pkgState.mProcesses.keyAt(iproc));
+                                        pw.println(")");
+                                        continue;
+                                    }
+                                    pw.print("      Process ");
+                                    pw.print(pkgState.mProcesses.keyAt(iproc));
+                                    if (proc.getCommonProcess().isMultiPackage()) {
+                                        pw.print(" (multi, ");
+                                    } else {
+                                        pw.print(" (unique, ");
+                                    }
+                                    pw.print(proc.getDurationsBucketCount());
+                                    pw.print(" entries)");
+                                    pw.println(":");
+                                    proc.dumpProcessState(pw, "        ", ALL_SCREEN_ADJ,
+                                            ALL_MEM_ADJ,
+                                            ALL_PROC_STATES, now);
+                                    proc.dumpPss(pw, "        ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+                                            ALL_PROC_STATES, now);
+                                    proc.dumpInternalLocked(pw, "        ", dumpAll);
+                                }
+                            } else {
+                                ArrayList<ProcessState> procs = new ArrayList<ProcessState>();
+                                for (int iproc = 0; iproc < NPROCS; iproc++) {
+                                    ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+                                    if (!pkgMatch && !reqPackage.equals(proc.getName())) {
+                                        continue;
+                                    }
+                                    if (activeOnly && !proc.isInUse()) {
+                                        continue;
+                                    }
+                                    procs.add(proc);
+                                }
+                                DumpUtils.dumpProcessSummaryLocked(pw, "      ", "Prc ", procs,
+                                        ALL_SCREEN_ADJ, ALL_MEM_ADJ, NON_CACHED_PROC_STATES,
+                                        now, totalTime);
                             }
-                            if (activeOnly && !proc.isInUse()) {
-                                continue;
+                        }
+                        if ((section & REPORT_PKG_SVC_STATS) != 0) {
+                            for (int isvc = 0; isvc < NSRVS; isvc++) {
+                                ServiceState svc = pkgState.mServices.valueAt(isvc);
+                                if (!pkgMatch && !reqPackage.equals(svc.getProcessName())) {
+                                    continue;
+                                }
+                                if (activeOnly && !svc.isInUse()) {
+                                    pw.print("      (Not active service: ");
+                                    pw.print(pkgState.mServices.keyAt(isvc));
+                                    pw.println(")");
+                                    continue;
+                                }
+                                if (dumpAll) {
+                                    pw.print("      Service ");
+                                } else {
+                                    pw.print("      * Svc ");
+                                }
+                                pw.print(pkgState.mServices.keyAt(isvc));
+                                pw.println(":");
+                                pw.print("        Process: ");
+                                pw.println(svc.getProcessName());
+                                svc.dumpStats(pw, "        ", "          ", "    ",
+                                        now, totalTime, dumpSummary, dumpAll);
                             }
-                            procs.add(proc);
                         }
-                        DumpUtils.dumpProcessSummaryLocked(pw, "      ", "Prc ", procs,
-                                ALL_SCREEN_ADJ, ALL_MEM_ADJ, NON_CACHED_PROC_STATES,
-                                now, totalTime);
-                    }
-                    for (int isvc=0; isvc<NSRVS; isvc++) {
-                        ServiceState svc = pkgState.mServices.valueAt(isvc);
-                        if (!pkgMatch && !reqPackage.equals(svc.getProcessName())) {
-                            continue;
+                        if ((section & REPORT_PKG_ASC_STATS) != 0) {
+                            for (int iasc = 0; iasc < NASCS; iasc++) {
+                                AssociationState asc = pkgState.mAssociations.valueAt(iasc);
+                                if (!pkgMatch && !reqPackage.equals(asc.getProcessName())) {
+                                    continue;
+                                }
+                                if (activeOnly && !asc.isInUse()) {
+                                    pw.print("      (Not active association: ");
+                                    pw.print(pkgState.mAssociations.keyAt(iasc));
+                                    pw.println(")");
+                                    continue;
+                                }
+                                if (dumpAll) {
+                                    pw.print("      Association ");
+                                } else {
+                                    pw.print("      * Asc ");
+                                }
+                                pw.print(pkgState.mAssociations.keyAt(iasc));
+                                pw.println(":");
+                                pw.print("        Process: ");
+                                pw.println(asc.getProcessName());
+                                asc.dumpStats(pw, "        ", "          ", "    ",
+                                        now, totalTime, dumpDetails, dumpAll);
+                            }
                         }
-                        if (activeOnly && !svc.isInUse()) {
-                            pw.print("      (Not active service: ");
-                                    pw.print(pkgState.mServices.keyAt(isvc)); pw.println(")");
-                            continue;
-                        }
-                        if (dumpAll) {
-                            pw.print("      Service ");
-                        } else {
-                            pw.print("      * Svc ");
-                        }
-                        pw.print(pkgState.mServices.keyAt(isvc));
-                        pw.println(":");
-                        pw.print("        Process: "); pw.println(svc.getProcessName());
-                        svc.dumpStats(pw, "        ", "          ", "    ",
-                                now, totalTime, dumpSummary, dumpAll);
-                    }
-                    for (int iasc=0; iasc<NASCS; iasc++) {
-                        AssociationState asc = pkgState.mAssociations.valueAt(iasc);
-                        if (!pkgMatch && !reqPackage.equals(asc.getProcessName())) {
-                            continue;
-                        }
-                        if (activeOnly && !asc.isInUse()) {
-                            pw.print("      (Not active association: ");
-                            pw.print(pkgState.mAssociations.keyAt(iasc)); pw.println(")");
-                            continue;
-                        }
-                        if (dumpAll) {
-                            pw.print("      Association ");
-                        } else {
-                            pw.print("      * Asc ");
-                        }
-                        pw.print(pkgState.mAssociations.keyAt(iasc));
-                        pw.println(":");
-                        pw.print("        Process: "); pw.println(asc.getProcessName());
-                        asc.dumpStats(pw, "        ", "          ", "    ",
-                                now, totalTime, dumpDetails, dumpAll);
                     }
                 }
             }
         }
 
-        ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
-        printedHeader = false;
-        int numShownProcs = 0, numTotalProcs = 0;
-        for (int ip=0; ip<procMap.size(); ip++) {
-            String procName = procMap.keyAt(ip);
-            SparseArray<ProcessState> uids = procMap.valueAt(ip);
-            for (int iu=0; iu<uids.size(); iu++) {
-                int uid = uids.keyAt(iu);
-                numTotalProcs++;
-                final ProcessState proc = uids.valueAt(iu);
-                if (!proc.hasAnyData()) {
-                    continue;
+        if ((section & REPORT_PROC_STATS) != 0) {
+            ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+            printedHeader = false;
+            int numShownProcs = 0, numTotalProcs = 0;
+            for (int ip = 0; ip < procMap.size(); ip++) {
+                String procName = procMap.keyAt(ip);
+                SparseArray<ProcessState> uids = procMap.valueAt(ip);
+                for (int iu = 0; iu < uids.size(); iu++) {
+                    int uid = uids.keyAt(iu);
+                    numTotalProcs++;
+                    final ProcessState proc = uids.valueAt(iu);
+                    if (!proc.hasAnyData()) {
+                        continue;
+                    }
+                    if (!proc.isMultiPackage()) {
+                        continue;
+                    }
+                    if (reqPackage != null && !reqPackage.equals(procName)
+                            && !reqPackage.equals(proc.getPackage())) {
+                        continue;
+                    }
+                    numShownProcs++;
+                    if (sepNeeded) {
+                        pw.println();
+                    }
+                    sepNeeded = true;
+                    if (!printedHeader) {
+                        pw.println("Multi-Package Common Processes:");
+                        printedHeader = true;
+                    }
+                    if (activeOnly && !proc.isInUse()) {
+                        pw.print("      (Not active: ");
+                        pw.print(procName);
+                        pw.println(")");
+                        continue;
+                    }
+                    pw.print("  * ");
+                    pw.print(procName);
+                    pw.print(" / ");
+                    UserHandle.formatUid(pw, uid);
+                    pw.print(" (");
+                    pw.print(proc.getDurationsBucketCount());
+                    pw.print(" entries)");
+                    pw.println(":");
+                    proc.dumpProcessState(pw, "        ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+                            ALL_PROC_STATES, now);
+                    proc.dumpPss(pw, "        ", ALL_SCREEN_ADJ, ALL_MEM_ADJ, ALL_PROC_STATES, now);
+                    proc.dumpInternalLocked(pw, "        ", dumpAll);
                 }
-                if (!proc.isMultiPackage()) {
-                    continue;
-                }
-                if (reqPackage != null && !reqPackage.equals(procName)
-                        && !reqPackage.equals(proc.getPackage())) {
-                    continue;
-                }
-                numShownProcs++;
-                if (sepNeeded) {
-                    pw.println();
-                }
-                sepNeeded = true;
-                if (!printedHeader) {
-                    pw.println("Multi-Package Common Processes:");
-                    printedHeader = true;
-                }
-                if (activeOnly && !proc.isInUse()) {
-                    pw.print("      (Not active: "); pw.print(procName); pw.println(")");
-                    continue;
-                }
-                pw.print("  * "); pw.print(procName); pw.print(" / ");
-                        UserHandle.formatUid(pw, uid);
-                        pw.print(" ("); pw.print(proc.getDurationsBucketCount());
-                        pw.print(" entries)"); pw.println(":");
-                proc.dumpProcessState(pw, "        ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
-                        ALL_PROC_STATES, now);
-                proc.dumpPss(pw, "        ", ALL_SCREEN_ADJ, ALL_MEM_ADJ, ALL_PROC_STATES, now);
-                proc.dumpInternalLocked(pw, "        ", dumpAll);
             }
+            pw.print("  Total procs: "); pw.print(numShownProcs);
+            pw.print(" shown of "); pw.print(numTotalProcs); pw.println(" total");
         }
 
         if (dumpAll) {
@@ -1598,8 +1646,7 @@
                 pw.println();
             }
             sepNeeded = true;
-            pw.print("  Total procs: "); pw.print(numShownProcs);
-                    pw.print(" shown of "); pw.print(numTotalProcs); pw.println(" total");
+
             if (mTrackingAssociations.size() > 0) {
                 pw.println();
                 pw.println("Tracking associations:");
@@ -1866,7 +1913,10 @@
         return outProcs;
     }
 
-    public void dumpCheckinLocked(PrintWriter pw, String reqPackage) {
+    /**
+     * Prints checkin style stats dump.
+     */
+    public void dumpCheckinLocked(PrintWriter pw, String reqPackage, int section) {
         final long now = SystemClock.uptimeMillis();
         final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
                 mPackages.getMap();
@@ -1895,50 +1945,61 @@
         }
         pw.println();
         pw.print("config,"); pw.println(mRuntime);
-        for (int ip=0; ip<pkgMap.size(); ip++) {
-            final String pkgName = pkgMap.keyAt(ip);
-            if (reqPackage != null && !reqPackage.equals(pkgName)) {
-                continue;
-            }
-            final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
-            for (int iu=0; iu<uids.size(); iu++) {
-                final int uid = uids.keyAt(iu);
-                final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu);
-                for (int iv=0; iv<vpkgs.size(); iv++) {
-                    final long vers = vpkgs.keyAt(iv);
-                    final PackageState pkgState = vpkgs.valueAt(iv);
-                    final int NPROCS = pkgState.mProcesses.size();
-                    final int NSRVS = pkgState.mServices.size();
-                    final int NASCS = pkgState.mAssociations.size();
-                    for (int iproc=0; iproc<NPROCS; iproc++) {
-                        ProcessState proc = pkgState.mProcesses.valueAt(iproc);
-                        proc.dumpPackageProcCheckin(pw, pkgName, uid, vers,
-                                pkgState.mProcesses.keyAt(iproc), now);
-                    }
-                    for (int isvc=0; isvc<NSRVS; isvc++) {
-                        final String serviceName = DumpUtils.collapseString(pkgName,
-                                pkgState.mServices.keyAt(isvc));
-                        final ServiceState svc = pkgState.mServices.valueAt(isvc);
-                        svc.dumpTimesCheckin(pw, pkgName, uid, vers, serviceName, now);
-                    }
-                    for (int iasc=0; iasc<NASCS; iasc++) {
-                        final String associationName = DumpUtils.collapseString(pkgName,
-                                pkgState.mAssociations.keyAt(iasc));
-                        final AssociationState asc = pkgState.mAssociations.valueAt(iasc);
-                        asc.dumpTimesCheckin(pw, pkgName, uid, vers, associationName, now);
+
+        if ((section & REPORT_PKG_STATS) != 0) {
+            for (int ip = 0; ip < pkgMap.size(); ip++) {
+                final String pkgName = pkgMap.keyAt(ip);
+                if (reqPackage != null && !reqPackage.equals(pkgName)) {
+                    continue;
+                }
+                final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+                for (int iu = 0; iu < uids.size(); iu++) {
+                    final int uid = uids.keyAt(iu);
+                    final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu);
+                    for (int iv = 0; iv < vpkgs.size(); iv++) {
+                        final long vers = vpkgs.keyAt(iv);
+                        final PackageState pkgState = vpkgs.valueAt(iv);
+                        final int NPROCS = pkgState.mProcesses.size();
+                        final int NSRVS = pkgState.mServices.size();
+                        final int NASCS = pkgState.mAssociations.size();
+                        if ((section & REPORT_PKG_PROC_STATS) != 0) {
+                            for (int iproc = 0; iproc < NPROCS; iproc++) {
+                                ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+                                proc.dumpPackageProcCheckin(pw, pkgName, uid, vers,
+                                        pkgState.mProcesses.keyAt(iproc), now);
+                            }
+                        }
+                        if ((section & REPORT_PKG_SVC_STATS) != 0) {
+                            for (int isvc = 0; isvc < NSRVS; isvc++) {
+                                final String serviceName = DumpUtils.collapseString(pkgName,
+                                        pkgState.mServices.keyAt(isvc));
+                                final ServiceState svc = pkgState.mServices.valueAt(isvc);
+                                svc.dumpTimesCheckin(pw, pkgName, uid, vers, serviceName, now);
+                            }
+                        }
+                        if ((section & REPORT_PKG_ASC_STATS) != 0) {
+                            for (int iasc = 0; iasc < NASCS; iasc++) {
+                                final String associationName = DumpUtils.collapseString(pkgName,
+                                        pkgState.mAssociations.keyAt(iasc));
+                                final AssociationState asc = pkgState.mAssociations.valueAt(iasc);
+                                asc.dumpTimesCheckin(pw, pkgName, uid, vers, associationName, now);
+                            }
+                        }
                     }
                 }
             }
         }
 
-        ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
-        for (int ip=0; ip<procMap.size(); ip++) {
-            String procName = procMap.keyAt(ip);
-            SparseArray<ProcessState> uids = procMap.valueAt(ip);
-            for (int iu=0; iu<uids.size(); iu++) {
-                final int uid = uids.keyAt(iu);
-                final ProcessState procState = uids.valueAt(iu);
-                procState.dumpProcCheckin(pw, procName, uid, now);
+        if ((section & REPORT_PROC_STATS) != 0) {
+            ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+            for (int ip = 0; ip < procMap.size(); ip++) {
+                String procName = procMap.keyAt(ip);
+                SparseArray<ProcessState> uids = procMap.valueAt(ip);
+                for (int iu = 0; iu < uids.size(); iu++) {
+                    final int uid = uids.keyAt(iu);
+                    final ProcessState procState = uids.valueAt(iu);
+                    procState.dumpProcCheckin(pw, procName, uid, now);
+                }
             }
         }
         pw.print("total");
@@ -2013,9 +2074,10 @@
         }
     }
 
-    public void writeToProto(ProtoOutputStream proto, long fieldId, long now) {
-        final long token = proto.start(fieldId);
-
+    /**
+     * Writes to ProtoOutputStream.
+     */
+    public void writeToProto(ProtoOutputStream proto, long now, int section) {
         proto.write(ProcessStatsSectionProto.START_REALTIME_MS, mTimePeriodStartRealtime);
         proto.write(ProcessStatsSectionProto.END_REALTIME_MS,
                 mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime);
@@ -2024,15 +2086,15 @@
         proto.write(ProcessStatsSectionProto.RUNTIME, mRuntime);
         proto.write(ProcessStatsSectionProto.HAS_SWAPPED_PSS, mHasSwappedOutPss);
         boolean partial = true;
-        if ((mFlags&FLAG_SHUTDOWN) != 0) {
+        if ((mFlags & FLAG_SHUTDOWN) != 0) {
             proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_SHUTDOWN);
             partial = false;
         }
-        if ((mFlags&FLAG_SYSPROPS) != 0) {
+        if ((mFlags & FLAG_SYSPROPS) != 0) {
             proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_SYSPROPS);
             partial = false;
         }
-        if ((mFlags&FLAG_COMPLETE) != 0) {
+        if ((mFlags & FLAG_COMPLETE) != 0) {
             proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_COMPLETE);
             partial = false;
         }
@@ -2041,31 +2103,34 @@
         }
 
         final ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
-        for (int ip=0; ip<procMap.size(); ip++) {
-            final String procName = procMap.keyAt(ip);
-            final SparseArray<ProcessState> uids = procMap.valueAt(ip);
-            for (int iu=0; iu<uids.size(); iu++) {
-                final int uid = uids.keyAt(iu);
-                final ProcessState procState = uids.valueAt(iu);
-                procState.writeToProto(proto, ProcessStatsSectionProto.PROCESS_STATS, procName,
-                        uid, now);
-            }
-        }
-
-        final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
-                mPackages.getMap();
-        for (int ip = 0; ip < pkgMap.size(); ip++) {
-            final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
-            for (int iu = 0; iu < uids.size(); iu++) {
-                final LongSparseArray<PackageState> vers = uids.valueAt(iu);
-                for (int iv = 0; iv < vers.size(); iv++) {
-                    final PackageState pkgState = vers.valueAt(iv);
-                    pkgState.writeToProto(proto, ProcessStatsSectionProto.PACKAGE_STATS, now);
+        if ((section & REPORT_PROC_STATS) != 0) {
+            for (int ip = 0; ip < procMap.size(); ip++) {
+                final String procName = procMap.keyAt(ip);
+                final SparseArray<ProcessState> uids = procMap.valueAt(ip);
+                for (int iu = 0; iu < uids.size(); iu++) {
+                    final int uid = uids.keyAt(iu);
+                    final ProcessState procState = uids.valueAt(iu);
+                    procState.writeToProto(proto, ProcessStatsSectionProto.PROCESS_STATS, procName,
+                            uid, now);
                 }
             }
         }
 
-        proto.end(token);
+        if ((section & REPORT_PKG_STATS) != 0) {
+            final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
+                    mPackages.getMap();
+            for (int ip = 0; ip < pkgMap.size(); ip++) {
+                final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+                for (int iu = 0; iu < uids.size(); iu++) {
+                    final LongSparseArray<PackageState> vers = uids.valueAt(iu);
+                    for (int iv = 0; iv < vers.size(); iv++) {
+                        final PackageState pkgState = vers.valueAt(iv);
+                        pkgState.writeToProto(proto, ProcessStatsSectionProto.PACKAGE_STATS, now,
+                                section);
+                    }
+                }
+            }
+        }
     }
 
     final public static class ProcessStateHolder {
@@ -2110,30 +2175,39 @@
             return as;
         }
 
-        public void writeToProto(ProtoOutputStream proto, long fieldId, long now) {
+        /**
+         * Writes the containing stats into proto, with options to choose smaller sections.
+         */
+        public void writeToProto(ProtoOutputStream proto, long fieldId, long now, int section) {
             final long token = proto.start(fieldId);
 
             proto.write(ProcessStatsPackageProto.PACKAGE, mPackageName);
             proto.write(ProcessStatsPackageProto.UID, mUid);
             proto.write(ProcessStatsPackageProto.VERSION, mVersionCode);
 
-            for (int ip = 0; ip < mProcesses.size(); ip++) {
-                final String procName = mProcesses.keyAt(ip);
-                final ProcessState procState = mProcesses.valueAt(ip);
-                procState.writeToProto(proto, ProcessStatsPackageProto.PROCESS_STATS, procName,
-                        mUid, now);
+            if ((section & ProcessStats.REPORT_PKG_PROC_STATS) != 0) {
+                for (int ip = 0; ip < mProcesses.size(); ip++) {
+                    final String procName = mProcesses.keyAt(ip);
+                    final ProcessState procState = mProcesses.valueAt(ip);
+                    procState.writeToProto(proto, ProcessStatsPackageProto.PROCESS_STATS, procName,
+                            mUid, now);
+                }
             }
 
-            for (int is = 0; is < mServices.size(); is++) {
-                final ServiceState serviceState = mServices.valueAt(is);
-                serviceState.writeToProto(proto, ProcessStatsPackageProto.SERVICE_STATS,
-                        now);
+            if ((section & ProcessStats.REPORT_PKG_SVC_STATS) != 0) {
+                for (int is = 0; is < mServices.size(); is++) {
+                    final ServiceState serviceState = mServices.valueAt(is);
+                    serviceState.writeToProto(proto, ProcessStatsPackageProto.SERVICE_STATS,
+                            now);
+                }
             }
 
-            for (int ia=0; ia<mAssociations.size(); ia++) {
-                final AssociationState ascState = mAssociations.valueAt(ia);
-                ascState.writeToProto(proto, ProcessStatsPackageProto.ASSOCIATION_STATS,
-                        now);
+            if ((section & ProcessStats.REPORT_PKG_ASC_STATS) != 0) {
+                for (int ia = 0; ia < mAssociations.size(); ia++) {
+                    final AssociationState ascState = mAssociations.valueAt(ia);
+                    ascState.writeToProto(proto, ProcessStatsPackageProto.ASSOCIATION_STATS,
+                            now);
+                }
             }
 
             proto.end(token);
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
index b33a5c4..81dab2f 100644
--- a/core/java/com/android/internal/content/FileSystemProvider.java
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -232,6 +232,7 @@
         displayName = FileUtils.buildValidFatFilename(displayName);
 
         final File before = getFileForDocId(docId);
+        final File beforeVisibleFile = getFileForDocId(docId, true);
         final File after = FileUtils.buildUniqueFile(before.getParentFile(), displayName);
         if (!before.renameTo(after)) {
             throw new IllegalStateException("Failed to rename to " + after);
@@ -241,7 +242,6 @@
         onDocIdChanged(docId);
         onDocIdChanged(afterDocId);
 
-        final File beforeVisibleFile = getFileForDocId(docId, true);
         final File afterVisibleFile = getFileForDocId(afterDocId, true);
         moveInMediaStore(beforeVisibleFile, afterVisibleFile);
 
diff --git a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
index c32894d..2671781 100644
--- a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
+++ b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
@@ -28,7 +28,6 @@
 interface IInputMethodPrivilegedOperations {
     void setImeWindowStatus(int vis, int backDisposition);
     void reportStartInput(in IBinder startInputToken);
-    void clearLastInputMethodWindowForTransition();
     IInputContentUriToken createInputContentUriToken(in Uri contentUri, in String packageName);
     void reportFullscreenMode(boolean fullscreen);
     void setInputMethod(String id);
diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
index f0e8dc5..cdb986a 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
@@ -135,22 +135,6 @@
     }
 
     /**
-     * Calls {@link IInputMethodPrivilegedOperations#clearLastInputMethodWindowForTransition()}.
-     */
-    @AnyThread
-    public void clearLastInputMethodWindowForTransition() {
-        final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
-        if (ops == null) {
-            return;
-        }
-        try {
-            ops.clearLastInputMethodWindowForTransition();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
      * Calls {@link IInputMethodPrivilegedOperations#createInputContentUriToken(Uri, String)}.
      *
      * @param contentUri Content URI to which a temporary read permission should be granted
diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperationsRegistry.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperationsRegistry.java
index 3255153..1436aed 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperationsRegistry.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperationsRegistry.java
@@ -29,12 +29,19 @@
 /**
  * A weak-reference-based mapper from IME token to {@link InputMethodPrivilegedOperations} that is
  * used only to support deprecated IME APIs in {@link android.view.inputmethod.InputMethodManager}.
+ *
+ * <p>This class is designed to be used as a per-process global registry.</p>
  */
 public final class InputMethodPrivilegedOperationsRegistry {
-    private final Object mLock = new Object();
-    @GuardedBy("mLock")
-    private final WeakHashMap<IBinder, WeakReference<InputMethodPrivilegedOperations>>
-            mRegistry = new WeakHashMap<>();
+    private InputMethodPrivilegedOperationsRegistry() {
+        // Not intended to be instantiated.
+    }
+
+    private static final Object sLock = new Object();
+
+    @Nullable
+    @GuardedBy("sLock")
+    private static WeakHashMap<IBinder, WeakReference<InputMethodPrivilegedOperations>> sRegistry;
 
     @Nullable
     private static InputMethodPrivilegedOperations sNop;
@@ -62,10 +69,13 @@
      * @param ops {@link InputMethodPrivilegedOperations} to be associated with the given IME token
      */
     @AnyThread
-    public void put(IBinder token, InputMethodPrivilegedOperations ops) {
-        synchronized (mLock) {
+    public static void put(IBinder token, InputMethodPrivilegedOperations ops) {
+        synchronized (sLock) {
+            if (sRegistry == null) {
+                sRegistry = new WeakHashMap<>();
+            }
             final WeakReference<InputMethodPrivilegedOperations> previousOps =
-                    mRegistry.put(token, new WeakReference<>(ops));
+                    sRegistry.put(token, new WeakReference<>(ops));
             if (previousOps != null) {
                 throw new IllegalStateException(previousOps.get() + " is already registered for "
                         + " this token=" + token + " newOps=" + ops);
@@ -84,9 +94,12 @@
      */
     @NonNull
     @AnyThread
-    public InputMethodPrivilegedOperations get(IBinder token) {
-        synchronized (mLock) {
-            final WeakReference<InputMethodPrivilegedOperations> wrapperRef = mRegistry.get(token);
+    public static InputMethodPrivilegedOperations get(IBinder token) {
+        synchronized (sLock) {
+            if (sRegistry == null) {
+                return getNopOps();
+            }
+            final WeakReference<InputMethodPrivilegedOperations> wrapperRef = sRegistry.get(token);
             if (wrapperRef == null) {
                 return getNopOps();
             }
@@ -108,9 +121,15 @@
      * @param token IME token to be removed.
      */
     @AnyThread
-    public void remove(IBinder token) {
-        synchronized (mLock) {
-            mRegistry.remove(token);
+    public static void remove(IBinder token) {
+        synchronized (sLock) {
+            if (sRegistry == null) {
+                return;
+            }
+            sRegistry.remove(token);
+            if (sRegistry.isEmpty()) {
+                sRegistry = null;
+            }
         }
     }
 }
diff --git a/core/java/com/android/internal/inputmethod/SubtypeLocaleUtils.java b/core/java/com/android/internal/inputmethod/SubtypeLocaleUtils.java
new file mode 100644
index 0000000..9ea4fa2
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/SubtypeLocaleUtils.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.inputmethod;
+
+import android.annotation.Nullable;
+import android.text.TextUtils;
+
+import java.util.Locale;
+
+/**
+ * A utility class to handle {@link Locale} related logic for
+ * {@link android.view.inputmethod.InputMethodSubtype} and
+ * {@link android.view.textservice.SpellCheckerSubtype}.
+ */
+public class SubtypeLocaleUtils {
+    /**
+     * Maintains deprecated logic about how subtype locales specified in XML resources have been
+     * parsed.
+     *
+     * <p>This logic is kept basically for compatibility purpose.  Consider relying on languageTag
+     * attribute instead.</p>
+     *
+     * @param localeStr string representation that is specified in the locale attribute
+     * @return {@link Locale} object parsed from {@code localeStr}. {@code null} for unexpected
+     *         format
+     *
+     * @attr ref android.R.styleable#InputMethod_Subtype_imeSubtypeLocale
+     * @attr ref android.R.styleable#InputMethod_Subtype_languageTag
+     * @attr ref android.R.styleable#SpellChecker_Subtype_languageTag
+     * @attr ref android.R.styleable#SpellChecker_Subtype_subtypeLocale
+     */
+    @Nullable
+    public static Locale constructLocaleFromString(String localeStr) {
+        if (TextUtils.isEmpty(localeStr)) {
+            return null;
+        }
+        // TODO: Use {@link Locale#toLanguageTag()} and {@link Locale#forLanguageTag(languageTag)}.
+        String[] localeParams = localeStr.split("_", 3);
+        if (localeParams.length >= 1 && "tl".equals(localeParams[0])) {
+            // Convert a locale whose language is "tl" to one whose language is "fil".
+            // For example, "tl_PH" will get converted to "fil_PH".
+            // Versions of Android earlier than Lollipop did not support three letter language
+            // codes, and used "tl" (Tagalog) as the language string for "fil" (Filipino).
+            // On Lollipop and above, the current three letter version must be used.
+            localeParams[0] = "fil";
+        }
+        // The length of localeStr is guaranteed to always return a 1 <= value <= 3
+        // because localeStr is not empty.
+        if (localeParams.length == 1) {
+            return new Locale(localeParams[0]);
+        } else if (localeParams.length == 2) {
+            return new Locale(localeParams[0], localeParams[1]);
+        } else if (localeParams.length == 3) {
+            return new Locale(localeParams[0], localeParams[1], localeParams[2]);
+        }
+        return null;
+    }
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index d0795c9..33b9ff7 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -337,6 +337,9 @@
 
     private final PlatformIdleStateCallback mPlatformIdleStateCallback;
 
+    /**
+     * This handler is running on {@link BackgroundThread}.
+     */
     final class MyHandler extends Handler {
         public MyHandler(Looper looper) {
             super(looper, null, true);
@@ -5758,8 +5761,6 @@
         for (int i = 0; i < N; i++) {
             int uid = mapUid(ws.get(i));
             getUidStatsLocked(uid).noteBluetoothScanResultsLocked(numNewResults);
-            StatsLog.write_non_chained(StatsLog.BLE_SCAN_RESULT_RECEIVED, ws.get(i), ws.getName(i),
-                    numNewResults);
         }
 
         final List<WorkChain> workChains = ws.getWorkChains();
@@ -5768,8 +5769,6 @@
                 final WorkChain wc = workChains.get(i);
                 int uid = mapUid(wc.getAttributionUid());
                 getUidStatsLocked(uid).noteBluetoothScanResultsLocked(numNewResults);
-                StatsLog.write(StatsLog.BLE_SCAN_RESULT_RECEIVED,
-                        wc.getUids(), wc.getTags(), numNewResults);
             }
         }
     }
diff --git a/core/java/com/android/internal/os/KernelCpuProcReader.java b/core/java/com/android/internal/os/KernelCpuProcReader.java
index 396deb4..c233ea8 100644
--- a/core/java/com/android/internal/os/KernelCpuProcReader.java
+++ b/core/java/com/android/internal/os/KernelCpuProcReader.java
@@ -24,13 +24,14 @@
 
 import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.io.InputStream;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
-import java.nio.channels.FileChannel;
+import java.nio.file.Files;
 import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-import java.nio.file.StandardOpenOption;
+import java.util.Arrays;
 
 /**
  * Reads cpu time proc files with throttling (adjustable interval).
@@ -55,7 +56,6 @@
     private static final int ERROR_THRESHOLD = 5;
     // Throttle interval in milliseconds
     private static final long DEFAULT_THROTTLE_INTERVAL = 3000L;
-    private static final int INITIAL_BUFFER_SIZE = 8 * 1024;
     private static final int MAX_BUFFER_SIZE = 1024 * 1024;
     private static final String PROC_UID_FREQ_TIME = "/proc/uid_cpupower/time_in_state";
     private static final String PROC_UID_ACTIVE_TIME = "/proc/uid_cpupower/concurrent_active_time";
@@ -84,13 +84,12 @@
     private long mThrottleInterval = DEFAULT_THROTTLE_INTERVAL;
     private long mLastReadTime = Long.MIN_VALUE;
     private final Path mProc;
-    private ByteBuffer mBuffer;
+    private byte[] mBuffer = new byte[8 * 1024];
+    private int mContentSize;
 
     @VisibleForTesting
     public KernelCpuProcReader(String procFile) {
         mProc = Paths.get(procFile);
-        mBuffer = ByteBuffer.allocateDirect(INITIAL_BUFFER_SIZE);
-        mBuffer.clear();
     }
 
     /**
@@ -108,38 +107,45 @@
             return null;
         }
         if (SystemClock.elapsedRealtime() < mLastReadTime + mThrottleInterval) {
-            if (mBuffer.limit() > 0 && mBuffer.limit() < mBuffer.capacity()) {
-                // mBuffer has data.
-                return mBuffer.asReadOnlyBuffer().order(ByteOrder.nativeOrder());
+            if (mContentSize > 0) {
+                return ByteBuffer.wrap(mBuffer, 0, mContentSize).asReadOnlyBuffer()
+                        .order(ByteOrder.nativeOrder());
             }
             return null;
         }
         mLastReadTime = SystemClock.elapsedRealtime();
-        mBuffer.clear();
+        mContentSize = 0;
         final int oldMask = StrictMode.allowThreadDiskReadsMask();
-        try (FileChannel fc = FileChannel.open(mProc, StandardOpenOption.READ)) {
-            while (fc.read(mBuffer) == mBuffer.capacity()) {
-                if (!resize()) {
-                    mErrors++;
-                    Slog.e(TAG, "Proc file is too large: " + mProc);
-                    return null;
+        try (InputStream in = Files.newInputStream(mProc)) {
+            int numBytes = 0;
+            int curr;
+            while ((curr = in.read(mBuffer, numBytes, mBuffer.length - numBytes)) >= 0) {
+                numBytes += curr;
+                if (numBytes == mBuffer.length) {
+                    // Hit the limit. Resize mBuffer.
+                    if (mBuffer.length == MAX_BUFFER_SIZE) {
+                        mErrors++;
+                        Slog.e(TAG, "Proc file is too large: " + mProc);
+                        return null;
+                    }
+                    mBuffer = Arrays.copyOf(mBuffer,
+                            Math.min(mBuffer.length << 1, MAX_BUFFER_SIZE));
                 }
-                fc.position(0);
             }
+            mContentSize = numBytes;
+            return ByteBuffer.wrap(mBuffer, 0, mContentSize).asReadOnlyBuffer()
+                    .order(ByteOrder.nativeOrder());
         } catch (NoSuchFileException | FileNotFoundException e) {
             // Happens when the kernel does not provide this file. Not a big issue. Just log it.
             mErrors++;
             Slog.w(TAG, "File not exist: " + mProc);
-            return null;
         } catch (IOException e) {
             mErrors++;
             Slog.e(TAG, "Error reading: " + mProc, e);
-            return null;
         } finally {
             StrictMode.setThreadPolicyMask(oldMask);
         }
-        mBuffer.flip();
-        return mBuffer.asReadOnlyBuffer().order(ByteOrder.nativeOrder());
+        return null;
     }
 
     /**
@@ -153,14 +159,4 @@
             mThrottleInterval = throttleInterval;
         }
     }
-
-    private boolean resize() {
-        if (mBuffer.capacity() >= MAX_BUFFER_SIZE) {
-            return false;
-        }
-        int newSize = Math.min(mBuffer.capacity() << 1, MAX_BUFFER_SIZE);
-        // Slog.i(TAG, "Resize buffer " + mBuffer.capacity() + " => " + newSize);
-        mBuffer = ByteBuffer.allocateDirect(newSize);
-        return true;
-    }
 }
diff --git a/core/java/com/android/internal/os/LooperStats.java b/core/java/com/android/internal/os/LooperStats.java
index 02a8b22..e4724ff 100644
--- a/core/java/com/android/internal/os/LooperStats.java
+++ b/core/java/com/android/internal/os/LooperStats.java
@@ -17,6 +17,7 @@
 package com.android.internal.os;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -36,7 +37,7 @@
  * @hide Only for use within the system server.
  */
 public class LooperStats implements Looper.Observer {
-    private static final int TOKEN_POOL_SIZE = 50;
+    private static final int SESSION_POOL_SIZE = 50;
 
     @GuardedBy("mLock")
     private final SparseArray<Entry> mEntries = new SparseArray<>(512);
@@ -78,17 +79,19 @@
         }
 
         DispatchSession session = (DispatchSession) token;
-        Entry entry = getOrCreateEntry(msg);
-        synchronized (entry) {
-            entry.messageCount++;
-            if (session != DispatchSession.NOT_SAMPLED) {
-                entry.recordedMessageCount++;
-                long latency = getElapsedRealtimeMicro() - session.startTimeMicro;
-                long cpuUsage = getThreadTimeMicro() - session.cpuStartMicro;
-                entry.totalLatencyMicro += latency;
-                entry.maxLatencyMicro = Math.max(entry.maxLatencyMicro, latency);
-                entry.cpuUsageMicro += cpuUsage;
-                entry.maxCpuUsageMicro = Math.max(entry.maxCpuUsageMicro, cpuUsage);
+        Entry entry = findEntry(msg, /* allowCreateNew= */session != DispatchSession.NOT_SAMPLED);
+        if (entry != null) {
+            synchronized (entry) {
+                entry.messageCount++;
+                if (session != DispatchSession.NOT_SAMPLED) {
+                    entry.recordedMessageCount++;
+                    long latency = getElapsedRealtimeMicro() - session.startTimeMicro;
+                    long cpuUsage = getThreadTimeMicro() - session.cpuStartMicro;
+                    entry.totalLatencyMicro += latency;
+                    entry.maxLatencyMicro = Math.max(entry.maxLatencyMicro, latency);
+                    entry.cpuUsageMicro += cpuUsage;
+                    entry.maxCpuUsageMicro = Math.max(entry.maxCpuUsageMicro, cpuUsage);
+                }
             }
         }
 
@@ -102,10 +105,11 @@
         }
 
         DispatchSession session = (DispatchSession) token;
-        Entry entry = getOrCreateEntry(msg);
+        Entry entry = findEntry(msg, /* allowCreateNew= */true);
         synchronized (entry) {
             entry.exceptionCount++;
         }
+
         recycleSession(session);
     }
 
@@ -116,29 +120,29 @@
 
     /** Returns an array of {@link ExportedEntry entries} with the aggregated statistics. */
     public List<ExportedEntry> getEntries() {
-        final ArrayList<ExportedEntry> entries;
+        final ArrayList<ExportedEntry> exportedEntries;
         synchronized (mLock) {
             final int size = mEntries.size();
-            entries = new ArrayList<>(size);
+            exportedEntries = new ArrayList<>(size);
             for (int i = 0; i < size; i++) {
                 Entry entry = mEntries.valueAt(i);
                 synchronized (entry) {
-                    entries.add(new ExportedEntry(entry));
+                    exportedEntries.add(new ExportedEntry(entry));
                 }
             }
         }
         // Add the overflow and collision entries only if they have any data.
-        if (mOverflowEntry.messageCount > 0 || mOverflowEntry.exceptionCount > 0) {
-            synchronized (mOverflowEntry) {
-                entries.add(new ExportedEntry(mOverflowEntry));
+        maybeAddSpecialEntry(exportedEntries, mOverflowEntry);
+        maybeAddSpecialEntry(exportedEntries, mHashCollisionEntry);
+        return exportedEntries;
+    }
+
+    private void maybeAddSpecialEntry(List<ExportedEntry> exportedEntries, Entry specialEntry) {
+        synchronized (specialEntry) {
+            if (specialEntry.messageCount > 0 || specialEntry.exceptionCount > 0) {
+                exportedEntries.add(new ExportedEntry(specialEntry));
             }
         }
-        if (mHashCollisionEntry.messageCount > 0 || mHashCollisionEntry.exceptionCount > 0) {
-            synchronized (mHashCollisionEntry) {
-                entries.add(new ExportedEntry(mHashCollisionEntry));
-            }
-        }
-        return entries;
     }
 
     /** Removes all collected data. */
@@ -158,24 +162,28 @@
         mSamplingInterval = samplingInterval;
     }
 
-    @NonNull
-    private Entry getOrCreateEntry(Message msg) {
+    @Nullable
+    private Entry findEntry(Message msg, boolean allowCreateNew) {
         final boolean isInteractive = mDeviceState.isScreenInteractive();
         final int id = Entry.idFor(msg, isInteractive);
         Entry entry;
         synchronized (mLock) {
             entry = mEntries.get(id);
             if (entry == null) {
-                if (mEntries.size() >= mEntriesSizeCap) {
-                    // If over the size cap, track totals under a single entry.
+                if (!allowCreateNew) {
+                    return null;
+                } else if (mEntries.size() >= mEntriesSizeCap) {
+                    // If over the size cap track totals under OVERFLOW entry.
                     return mOverflowEntry;
+                } else {
+                    entry = new Entry(msg, isInteractive);
+                    mEntries.put(id, entry);
                 }
-                entry = new Entry(msg, isInteractive);
-                mEntries.put(id, entry);
             }
         }
 
-        if (entry.handler.getClass() != msg.getTarget().getClass()
+        if (entry.workSourceUid != msg.workSourceUid
+                || entry.handler.getClass() != msg.getTarget().getClass()
                 || entry.handler.getLooper().getThread() != msg.getTarget().getLooper().getThread()
                 || entry.isInteractive != isInteractive) {
             // If a hash collision happened, track totals under a single entry.
@@ -185,7 +193,7 @@
     }
 
     private void recycleSession(DispatchSession session) {
-        if (session != DispatchSession.NOT_SAMPLED && mSessionPool.size() < TOKEN_POOL_SIZE) {
+        if (session != DispatchSession.NOT_SAMPLED && mSessionPool.size() < SESSION_POOL_SIZE) {
             mSessionPool.add(session);
         }
     }
@@ -209,6 +217,7 @@
     }
 
     private static class Entry {
+        public final int workSourceUid;
         public final Handler handler;
         public final String messageName;
         public final boolean isInteractive;
@@ -221,12 +230,14 @@
         public long maxCpuUsageMicro;
 
         Entry(Message msg, boolean isInteractive) {
+            this.workSourceUid = msg.workSourceUid;
             this.handler = msg.getTarget();
             this.messageName = handler.getMessageName(msg);
             this.isInteractive = isInteractive;
         }
 
         Entry(String specialEntryName) {
+            this.workSourceUid = Message.UID_NONE;
             this.messageName = specialEntryName;
             this.handler = null;
             this.isInteractive = false;
@@ -244,6 +255,7 @@
 
         static int idFor(Message msg, boolean isInteractive) {
             int result = 7;
+            result = 31 * result + msg.workSourceUid;
             result = 31 * result + msg.getTarget().getLooper().getThread().hashCode();
             result = 31 * result + msg.getTarget().getClass().hashCode();
             result = 31 * result + (isInteractive ? 1231 : 1237);
@@ -257,6 +269,7 @@
 
     /** Aggregated data of Looper message dispatching in the in the current process. */
     public static class ExportedEntry {
+        public final int workSourceUid;
         public final String handlerClassName;
         public final String threadName;
         public final String messageName;
@@ -270,6 +283,7 @@
         public final long maxCpuUsageMicros;
 
         ExportedEntry(Entry entry) {
+            this.workSourceUid = entry.workSourceUid;
             if (entry.handler != null) {
                 this.handlerClassName = entry.handler.getClass().getName();
                 this.threadName = entry.handler.getLooper().getThread().getName();
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index c4214cf..9b8f120 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -141,7 +141,8 @@
     void showShutdownUi(boolean isReboot, String reason);
 
     // Used to show the dialog when BiometricService starts authentication
-    void showBiometricDialog(in Bundle bundle, IBiometricPromptReceiver receiver, int type);
+    void showBiometricDialog(in Bundle bundle, IBiometricPromptReceiver receiver, int type,
+            boolean requireConfirmation);
     // Used to hide the dialog when a biometric is authenticated
     void onBiometricAuthenticated();
     // Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index e48e733..90f2002 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -91,7 +91,8 @@
     void showPinningEscapeToast();
 
     // Used to show the dialog when BiometricService starts authentication
-    void showBiometricDialog(in Bundle bundle, IBiometricPromptReceiver receiver, int type);
+    void showBiometricDialog(in Bundle bundle, IBiometricPromptReceiver receiver, int type,
+            boolean requireConfirmation);
     // Used to hide the dialog when a biometric is authenticated
     void onBiometricAuthenticated();
     // Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
diff --git a/core/java/com/android/internal/util/ContrastColorUtil.java b/core/java/com/android/internal/util/ContrastColorUtil.java
index 1038199..a403c06 100644
--- a/core/java/com/android/internal/util/ContrastColorUtil.java
+++ b/core/java/com/android/internal/util/ContrastColorUtil.java
@@ -523,8 +523,9 @@
     }
 
     public static int resolveAmbientColor(Context context, int notificationColor) {
-        final int resolvedColor = resolveColor(context, notificationColor,
-                true /* defaultBackgroundIsDark */);
+        final int resolvedColor = notificationColor == Notification.COLOR_DEFAULT
+                ? context.getColor(com.android.internal.R.color.notification_default_color_dark)
+                : notificationColor;
 
         int color = resolvedColor;
         color = ContrastColorUtil.ensureTextContrastOnBlack(color);
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index 6f9c87a..ececba1 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -68,7 +69,7 @@
 
     @GuardedBy("mLock")
     @Nullable
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private InputConnection mInputConnection;
 
     private Looper mMainLooper;
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 543f4a5..5f1243f 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -31,6 +31,8 @@
  * applications.
  */
 interface IInputMethodManager {
+    void addClient(in IInputMethodClient client, in IInputContext inputContext);
+
     // TODO: Use ParceledListSlice instead
     List<InputMethodInfo> getInputMethodList();
     List<InputMethodInfo> getVrInputMethodList();
diff --git a/core/java/com/android/internal/view/InputBindResult.java b/core/java/com/android/internal/view/InputBindResult.java
index 7548c22..101fd41 100644
--- a/core/java/com/android/internal/view/InputBindResult.java
+++ b/core/java/com/android/internal/view/InputBindResult.java
@@ -139,8 +139,7 @@
          * The client should try to restart input when its {@link android.view.Window} is focused
          * again.</p>
          *
-         * @see com.android.server.wm.WindowManagerInternal#inputMethodClientHasFocus(
-         * IInputMethodClient)
+         * @see com.android.server.wm.WindowManagerInternal#isInputMethodClientFocus(int, int)
          */
         int ERROR_NOT_IME_TARGET_WINDOW = 11;
         /**
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index 0b37d57..4773e16 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -840,7 +840,11 @@
                 scale *= 10;
             }
             value = (float) (Math.rint(value * scale) / scale);
-            
+
+            // Corner case: (int)-0.1 will become zero, so the negative sign gets lost
+            if ((int) value == 0 && value < 0) {
+                append("-");
+            }
             append((int) value);
 
             if (precision != 0) {
diff --git a/core/java/org/apache/http/conn/ssl/SSLSocketFactory.java b/core/java/org/apache/http/conn/ssl/SSLSocketFactory.java
index 65be161..b2e8b5e 100644
--- a/core/java/org/apache/http/conn/ssl/SSLSocketFactory.java
+++ b/core/java/org/apache/http/conn/ssl/SSLSocketFactory.java
@@ -37,6 +37,7 @@
 import org.apache.http.params.HttpParams;
 
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.KeyManager;
 import javax.net.ssl.KeyManagerFactory;
@@ -181,7 +182,7 @@
     private final javax.net.ssl.SSLSocketFactory socketfactory;
     @UnsupportedAppUsage
     private final HostNameResolver nameResolver;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private X509HostnameVerifier hostnameVerifier = BROWSER_COMPATIBLE_HOSTNAME_VERIFIER;
 
     public SSLSocketFactory(
@@ -251,7 +252,7 @@
      * This constructor is used exclusively to instantiate the factory for
      * {@link #getSocketFactory getSocketFactory}.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private SSLSocketFactory() {
         super();
         this.sslcontext = null;
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index bb8ee14..762b430 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -230,7 +230,6 @@
     static_libs: [
         "libgif",
         "libseccomp_policy",
-        "libselinux",
         "libgrallocusage",
         "libscrypt_static",
     ],
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 0a25271..897f6fa5 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -15,7 +15,6 @@
 #include "SkPM4f.h"
 #include "SkPM4fPriv.h"
 #include "GraphicsJNI.h"
-#include "SkDither.h"
 #include "SkUnPreMultiply.h"
 #include "SkStream.h"
 
@@ -326,33 +325,6 @@
     return true;
 }
 
-//////////////////// ToColor procs
-
-static void ToColor_SA8(SkColor dst[], const void* src, int width) {
-    SkASSERT(width > 0);
-    const uint8_t* s = (const uint8_t*)src;
-    do {
-        uint8_t c = *s++;
-        *dst++ = SkColorSetARGB(c, 0, 0, 0);
-    } while (--width != 0);
-}
-
-static void ToF16_SA8(void* dst, const void* src, int width) {
-    SkASSERT(width > 0);
-    uint64_t* d = (uint64_t*)dst;
-    const uint8_t* s = (const uint8_t*)src;
-
-    for (int i = 0; i < width; i++) {
-        uint8_t c = *s++;
-        SkPM4f a;
-        a.fVec[SkPM4f::R] = 0.0f;
-        a.fVec[SkPM4f::G] = 0.0f;
-        a.fVec[SkPM4f::B] = 0.0f;
-        a.fVec[SkPM4f::A] = c / 255.0f;
-        *d++ = a.toF16();
-    }
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -417,23 +389,12 @@
     SkImageInfo dstInfo = srcPM.info().makeColorType(dstCT);
     switch (dstCT) {
         case kRGB_565_SkColorType:
-            // copyTo() has never been strict on alpha type.  Here we set the src to opaque to
-            // allow the call to readPixels() to succeed and preserve this lenient behavior.
-            if (kOpaque_SkAlphaType != srcPM.alphaType()) {
-                srcPM = SkPixmap(srcPM.info().makeAlphaType(kOpaque_SkAlphaType), srcPM.addr(),
-                                 srcPM.rowBytes());
-                dstInfo = dstInfo.makeAlphaType(kOpaque_SkAlphaType);
-            }
+            dstInfo = dstInfo.makeAlphaType(kOpaque_SkAlphaType);
             break;
         case kRGBA_F16_SkColorType:
             // The caller does not have an opportunity to pass a dst color space.  Assume that
             // they want linear sRGB.
             dstInfo = dstInfo.makeColorSpace(SkColorSpace::MakeSRGBLinear());
-
-            if (!srcPM.colorSpace()) {
-                // Skia needs a color space to convert to F16.  nullptr should be treated as sRGB.
-                srcPM.setColorSpace(SkColorSpace::MakeSRGB());
-            }
             break;
         default:
             break;
@@ -446,57 +407,11 @@
         return false;
     }
 
-    // Skia does not support copying from kAlpha8 to types that are not alpha only.
-    // We will handle this case here.
-    if (kAlpha_8_SkColorType == srcPM.colorType() && kAlpha_8_SkColorType != dstCT) {
-        switch (dstCT) {
-            case kRGBA_8888_SkColorType:
-            case kBGRA_8888_SkColorType: {
-                for (int y = 0; y < src.height(); y++) {
-                    const uint8_t* srcRow = srcPM.addr8(0, y);
-                    uint32_t* dstRow = dst->getAddr32(0, y);
-                    ToColor_SA8(dstRow, srcRow, src.width());
-                }
-                return true;
-            }
-            case kRGB_565_SkColorType: {
-                for (int y = 0; y < src.height(); y++) {
-                    uint16_t* dstRow = dst->getAddr16(0, y);
-                    memset(dstRow, 0, sizeof(uint16_t) * src.width());
-                }
-                return true;
-            }
-            case kRGBA_F16_SkColorType: {
-               for (int y = 0; y < src.height(); y++) {
-                   const uint8_t* srcRow = srcPM.addr8(0, y);
-                   void* dstRow = dst->getAddr(0, y);
-                   ToF16_SA8(dstRow, srcRow, src.width());
-               }
-               return true;
-           }
-            default:
-                return false;
-        }
-    }
-
     SkPixmap dstPM;
     if (!dst->peekPixels(&dstPM)) {
         return false;
     }
 
-    // Skia needs a color space to convert from F16.  nullptr should be treated as sRGB.
-    if (kRGBA_F16_SkColorType == srcPM.colorType() && !dstPM.colorSpace()) {
-        dstPM.setColorSpace(SkColorSpace::MakeSRGB());
-    }
-
-    // readPixels does not support color spaces with parametric transfer functions.  This
-    // works around that restriction when the color spaces are equal.
-    if (kRGBA_F16_SkColorType != dstCT && kRGBA_F16_SkColorType != srcPM.colorType() &&
-            dstPM.colorSpace() == srcPM.colorSpace()) {
-        dstPM.setColorSpace(nullptr);
-        srcPM.setColorSpace(nullptr);
-    }
-
     return srcPM.readPixels(dstPM);
 }
 
diff --git a/core/jni/android/graphics/pdf/PdfDocument.cpp b/core/jni/android/graphics/pdf/PdfDocument.cpp
index e2dc52b..5f67d30 100644
--- a/core/jni/android/graphics/pdf/PdfDocument.cpp
+++ b/core/jni/android/graphics/pdf/PdfDocument.cpp
@@ -21,11 +21,11 @@
 
 #include "CreateJavaOutputStreamAdaptor.h"
 
-#include "SkDocument.h"
+#include "SkPDFDocument.h"
 #include "SkPicture.h"
 #include "SkPictureRecorder.h"
-#include "SkStream.h"
 #include "SkRect.h"
+#include "SkStream.h"
 
 #include <hwui/Canvas.h>
 
@@ -88,7 +88,7 @@
     }
 
     void write(SkWStream* stream) {
-        sk_sp<SkDocument> document = SkDocument::MakePDF(stream);
+        sk_sp<SkDocument> document = SkPDF::MakeDocument(stream);
         for (unsigned i = 0; i < mPages.size(); i++) {
             PageRecord* page =  mPages[i];
 
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index eba4c50..343aef2 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -674,7 +674,7 @@
     int ret = 0;
     ret |= RegisterMethodsOrDie(env, "android/graphics/Canvas", gMethods, NELEM(gMethods));
     ret |= RegisterMethodsOrDie(env, "android/graphics/BaseCanvas", gDrawMethods, NELEM(gDrawMethods));
-    ret |= RegisterMethodsOrDie(env, "android/view/RecordingCanvas", gDrawMethods, NELEM(gDrawMethods));
+    ret |= RegisterMethodsOrDie(env, "android/graphics/BaseRecordingCanvas", gDrawMethods, NELEM(gDrawMethods));
     return ret;
 
 }
diff --git a/core/jni/android_graphics_drawable_VectorDrawable.cpp b/core/jni/android_graphics_drawable_VectorDrawable.cpp
index 6f4a58a..58a2379 100644
--- a/core/jni/android_graphics_drawable_VectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_VectorDrawable.cpp
@@ -130,7 +130,7 @@
 
 static jfloat getRootAlpha(JNIEnv*, jobject, jlong treePtr) {
     VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
-    return tree->stagingProperties()->getRootAlpha();
+    return tree->stagingProperties().getRootAlpha();
 }
 
 static void updateFullPathPropertiesAndStrokeStyles(JNIEnv*, jobject, jlong fullPathPtr,
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 46b19bd..63b0046 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -444,6 +444,14 @@
     return reinterpret_cast<RenderNode*>(renderNodePtr)->stagingProperties().getHeight();
 }
 
+static jboolean android_view_RenderNode_setAllowForceDark(jlong renderNodePtr, jboolean allow) {
+    return SET_AND_DIRTY(setAllowForceDark, allow, RenderNode::GENERIC);
+}
+
+static jboolean android_view_RenderNode_getAllowForceDark(jlong renderNodePtr) {
+    return reinterpret_cast<RenderNode*>(renderNodePtr)->stagingProperties().getAllowForceDark();
+}
+
 // ----------------------------------------------------------------------------
 // RenderProperties - Animations
 // ----------------------------------------------------------------------------
@@ -465,8 +473,8 @@
 // SurfaceView position callback
 // ----------------------------------------------------------------------------
 
-jmethodID gSurfaceViewPositionUpdateMethod;
-jmethodID gSurfaceViewPositionLostMethod;
+jmethodID gPositionListener_PositionChangedMethod;
+jmethodID gPositionListener_PositionLostMethod;
 
 static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,
         jlong renderNodePtr, jobject surfaceview) {
@@ -523,7 +531,7 @@
                 return;
             }
 
-            env->CallVoidMethod(localref, gSurfaceViewPositionLostMethod,
+            env->CallVoidMethod(localref, gPositionListener_PositionLostMethod,
                     info ? info->canvasContext.getFrameNumber() : 0);
             env->DeleteLocalRef(localref);
         }
@@ -547,7 +555,7 @@
                 env->DeleteWeakGlobalRef(mWeakRef);
                 mWeakRef = nullptr;
             } else {
-                env->CallVoidMethod(localref, gSurfaceViewPositionUpdateMethod,
+                env->CallVoidMethod(localref, gPositionListener_PositionChangedMethod,
                         frameNumber, left, top, right, bottom);
                 env->DeleteLocalRef(localref);
             }
@@ -580,7 +588,7 @@
     { "nGetDebugSize",         "(J)I",    (void*) android_view_RenderNode_getDebugSize },
     { "nAddAnimator",              "(JJ)V", (void*) android_view_RenderNode_addAnimator },
     { "nEndAllAnimators",          "(J)V", (void*) android_view_RenderNode_endAllAnimators },
-    { "nRequestPositionUpdates",   "(JLandroid/view/SurfaceView;)V", (void*) android_view_RenderNode_requestPositionUpdates },
+    { "nRequestPositionUpdates",   "(JLandroid/view/RenderNode$PositionUpdateListener;)V", (void*) android_view_RenderNode_requestPositionUpdates },
     { "nSetDisplayList",       "(JJ)V",   (void*) android_view_RenderNode_setDisplayList },
 
 
@@ -664,14 +672,16 @@
     { "nGetPivotY",                "(J)F",  (void*) android_view_RenderNode_getPivotY },
     { "nGetWidth",                 "(J)I",  (void*) android_view_RenderNode_getWidth },
     { "nGetHeight",                "(J)I",  (void*) android_view_RenderNode_getHeight },
+    { "nSetAllowForceDark",        "(JZ)Z", (void*) android_view_RenderNode_setAllowForceDark },
+    { "nGetAllowForceDark",        "(J)Z",  (void*) android_view_RenderNode_getAllowForceDark },
 };
 
 int register_android_view_RenderNode(JNIEnv* env) {
-    jclass clazz = FindClassOrDie(env, "android/view/SurfaceView");
-    gSurfaceViewPositionUpdateMethod = GetMethodIDOrDie(env, clazz,
-            "updateSurfacePosition_renderWorker", "(JIIII)V");
-    gSurfaceViewPositionLostMethod = GetMethodIDOrDie(env, clazz,
-            "surfacePositionLost_uiRtSync", "(J)V");
+    jclass clazz = FindClassOrDie(env, "android/view/RenderNode$PositionUpdateListener");
+    gPositionListener_PositionChangedMethod = GetMethodIDOrDie(env, clazz,
+            "positionChanged", "(JIIII)V");
+    gPositionListener_PositionLostMethod = GetMethodIDOrDie(env, clazz,
+            "positionLost", "(J)V");
     return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 743b9f6..b70177f 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -157,23 +157,17 @@
     return Rect(left, top, right, bottom);
 }
 
-static jobject nativeScreenshotToBuffer(JNIEnv* env, jclass clazz,
+static jobject nativeScreenshot(JNIEnv* env, jclass clazz,
         jobject displayTokenObj, jobject sourceCropObj, jint width, jint height,
-        jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform,
-        int rotation) {
+        bool useIdentityTransform, int rotation) {
     sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
     if (displayToken == NULL) {
         return NULL;
     }
     Rect sourceCrop = rectFromObj(env, sourceCropObj);
-    if (allLayers) {
-        minLayer = INT32_MIN;
-        maxLayer = INT32_MAX;
-    }
     sp<GraphicBuffer> buffer;
-    status_t res = ScreenshotClient::capture(displayToken,
-            sourceCrop, width, height, minLayer, maxLayer, useIdentityTransform,
-            rotation, &buffer);
+    status_t res = ScreenshotClient::capture(displayToken, sourceCrop, width, height,
+            useIdentityTransform, rotation, &buffer);
     if (res != NO_ERROR) {
         return NULL;
     }
@@ -187,100 +181,6 @@
             (jlong)buffer.get());
 }
 
-static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz,
-        jobject displayTokenObj, jobject sourceCropObj, jint width, jint height,
-        jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform,
-        int rotation) {
-    sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
-    if (displayToken == NULL) {
-        return NULL;
-    }
-
-    Rect sourceCrop = rectFromObj(env, sourceCropObj);
-
-    std::unique_ptr<ScreenshotClient> screenshot(new ScreenshotClient());
-    status_t res;
-    if (allLayers) {
-        minLayer = INT32_MIN;
-        maxLayer = INT32_MAX;
-    }
-
-    sp<GraphicBuffer> buffer;
-    res = ScreenshotClient::capture(displayToken, sourceCrop, width, height,
-        minLayer, maxLayer, useIdentityTransform, static_cast<uint32_t>(rotation), &buffer);
-    if (res != NO_ERROR) {
-        return NULL;
-    }
-
-    SkColorType colorType;
-    SkAlphaType alphaType;
-
-    PixelFormat format = buffer->getPixelFormat();
-    switch (format) {
-        case PIXEL_FORMAT_RGBX_8888: {
-            colorType = kRGBA_8888_SkColorType;
-            alphaType = kOpaque_SkAlphaType;
-            break;
-        }
-        case PIXEL_FORMAT_RGBA_8888: {
-            colorType = kRGBA_8888_SkColorType;
-            alphaType = kPremul_SkAlphaType;
-            break;
-        }
-        case PIXEL_FORMAT_RGBA_FP16: {
-            colorType = kRGBA_F16_SkColorType;
-            alphaType = kPremul_SkAlphaType;
-            break;
-        }
-        case PIXEL_FORMAT_RGB_565: {
-            colorType = kRGB_565_SkColorType;
-            alphaType = kOpaque_SkAlphaType;
-            break;
-        }
-        default: {
-            return NULL;
-        }
-    }
-
-    SkImageInfo info = SkImageInfo::Make(buffer->getWidth(), buffer->getHeight(),
-                                         colorType, alphaType,
-                                         SkColorSpace::MakeSRGB());
-
-    auto bitmap = sk_sp<Bitmap>(new Bitmap(buffer.get(), info));
-    return bitmap::createBitmap(env, bitmap.release(),
-                                android::bitmap::kBitmapCreateFlag_Premultiplied, NULL);
-}
-
-static void nativeScreenshot(JNIEnv* env, jclass clazz, jobject displayTokenObj,
-        jobject surfaceObj, jobject sourceCropObj, jint width, jint height,
-        jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform) {
-    sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
-    if (displayToken == NULL) {
-        return;
-    }
-
-    sp<Surface> consumer = android_view_Surface_getSurface(env, surfaceObj);
-    if (consumer == NULL) {
-        return;
-    }
-
-    Rect sourceCrop;
-    if (sourceCropObj != NULL) {
-        sourceCrop = rectFromObj(env, sourceCropObj);
-    }
-
-    if (allLayers) {
-        minLayer = INT32_MIN;
-        maxLayer = INT32_MAX;
-    }
-
-    sp<GraphicBuffer> buffer;
-    ScreenshotClient::capture(displayToken, sourceCrop, width, height, minLayer, maxLayer,
-                              useIdentityTransform, 0, &buffer);
-
-    Surface::attachAndQueueBuffer(consumer.get(), buffer);
-}
-
 static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerHandleToken,
         jobject sourceCropObj, jfloat frameScale) {
 
@@ -919,10 +819,6 @@
             (void*)nativeDestroy },
     {"nativeDisconnect", "(J)V",
             (void*)nativeDisconnect },
-    {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/graphics/Rect;IIIIZZI)Landroid/graphics/Bitmap;",
-            (void*)nativeScreenshotBitmap },
-    {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/view/Surface;Landroid/graphics/Rect;IIIIZZ)V",
-            (void*)nativeScreenshot },
     {"nativeCreateTransaction", "()J",
             (void*)nativeCreateTransaction },
     {"nativeApplyTransaction", "(JZ)V",
@@ -1013,9 +909,8 @@
             (void*)nativeDestroyInTransaction },
     {"nativeGetHandle", "(J)Landroid/os/IBinder;",
             (void*)nativeGetHandle },
-    {"nativeScreenshotToBuffer",
-     "(Landroid/os/IBinder;Landroid/graphics/Rect;IIIIZZI)Landroid/graphics/GraphicBuffer;",
-     (void*)nativeScreenshotToBuffer },
+    {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/graphics/Rect;IIZI)Landroid/graphics/GraphicBuffer;",
+            (void*)nativeScreenshot },
     {"nativeCaptureLayers", "(Landroid/os/IBinder;Landroid/graphics/Rect;F)Landroid/graphics/GraphicBuffer;",
             (void*)nativeCaptureLayers },
 };
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 3c59bd1..7a5b604 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -1064,6 +1064,12 @@
     proxy->allocateBuffers(surface);
 }
 
+static void android_view_ThreadedRenderer_setForceDark(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jboolean enable) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    proxy->setForceDark(enable);
+}
+
 // ----------------------------------------------------------------------------
 // FrameMetricsObserver
 // ----------------------------------------------------------------------------
@@ -1177,6 +1183,7 @@
     { "nSetIsolatedProcess", "(Z)V", (void*)android_view_ThreadedRenderer_setIsolatedProcess },
     { "nSetContextPriority", "(I)V", (void*)android_view_ThreadedRenderer_setContextPriority },
     { "nAllocateBuffers", "(JLandroid/view/Surface;)V", (void*)android_view_ThreadedRenderer_allocateBuffers },
+    { "nSetForceDark", "(JZ)V", (void*)android_view_ThreadedRenderer_setForceDark },
 };
 
 static JavaVM* mJvm = nullptr;
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index 9d5f0bc..ab50ad1 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -130,6 +130,13 @@
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
     optional bool keyguard_showing = 1;
+    repeated KeyguardOccludedProto keyguard_occluded_states= 2;
+}
+
+message KeyguardOccludedProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional int32 display_id = 1;
     optional bool keyguard_occluded = 2;
 }
 
diff --git a/core/proto/android/server/backup_chunks_metadata.proto b/core/proto/android/server/backup_chunks_metadata.proto
new file mode 100644
index 0000000..a375f02
--- /dev/null
+++ b/core/proto/android/server/backup_chunks_metadata.proto
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+syntax = "proto2";
+package com.android.server.backup.encryption.chunk;
+
+option java_outer_classname = "ChunksMetadataProto";
+
+// Cipher type with which the chunks are encrypted. For now we only support AES/GCM/NoPadding, but
+// this is for backwards-compatibility in case we need to change the default Cipher in the future.
+enum CipherType {
+    UNKNOWN_CIPHER_TYPE = 0;
+    // Chunk is prefixed with a 12-byte nonce. The tag length is 16 bytes.
+    AES_256_GCM = 1;
+}
+
+// Checksum type with which the plaintext is verified.
+enum ChecksumType {
+    UNKNOWN_CHECKSUM_TYPE = 0;
+    SHA_256 = 1;
+}
+
+enum ChunkOrderingType {
+    CHUNK_ORDERING_TYPE_UNSPECIFIED = 0;
+    // The chunk ordering contains a list of the start position of each chunk in the encrypted file,
+    // ordered as in the plaintext file. This allows us to recreate the original plaintext file
+    // during decryption. We use this mode for full backups where the order of the data in the file
+    // is important.
+    EXPLICIT_STARTS = 1;
+    // The chunk ordering does not contain any start positions, and instead each encrypted chunk in
+    // the backup file is prefixed with its length. This allows us to decrypt each chunk but does
+    // not give any information about the order. However, we use this mode for key value backups
+    // where the order does not matter.
+    INLINE_LENGTHS = 2;
+}
+
+// Chunk entry (for local state)
+message Chunk {
+    // SHA-256 MAC of the plaintext of the chunk
+    optional bytes hash = 1;
+    // Number of bytes in encrypted chunk
+    optional int32 length = 2;
+}
+
+// List of the chunks in the blob, along with the length of each chunk. From this is it possible to
+// extract individual chunks. (i.e., start position is equal to the sum of the lengths of all
+// preceding chunks.)
+//
+// This is local state stored on the device. It is never sent to the backup server. See
+// ChunkOrdering for how the device restores the chunks in the correct order.
+// Next tag : 6
+message ChunkListing {
+    repeated Chunk chunks = 1;
+
+    // Cipher algorithm with which the chunks are encrypted.
+    optional CipherType cipher_type = 2;
+
+    // Defines the type of chunk order used to encode the backup file on the server, so that we can
+    // consistently use the same type between backups. If unspecified this backup file was created
+    // before INLINE_LENGTHS was supported, thus assume it is EXPLICIT_STARTS.
+    optional ChunkOrderingType chunk_ordering_type = 5;
+
+    // The document ID returned from Scotty server after uploading the blob associated with this
+    // listing. This needs to be sent when uploading new diff scripts.
+    optional string document_id = 3;
+
+    // Fingerprint mixer salt used for content defined chunking. This is randomly generated for each
+    // package during the initial non-incremental backup and reused for incremental backups.
+    optional bytes fingerprint_mixer_salt = 4;
+}
+
+// Ordering information about plaintext and checksum. This is used on restore to reconstruct the
+// blob in its correct order. (The chunk order is randomized so as to give the server less
+// information about which parts of the backup are changing over time.) This proto is encrypted
+// before being uploaded to the server, with a key unknown to the server.
+message ChunkOrdering {
+    // For backups where ChunksMetadata#chunk_ordering_type = EXPLICIT STARTS:
+    // Ordered start positions of chunks. i.e., the file is the chunk starting at this position,
+    // followed by the chunk starting at this position, followed by ... etc. You can compute the
+    // lengths of the chunks by sorting this list then looking at the start position of the next
+    // chunk after the chunk you care about. This is guaranteed to work as all chunks are
+    // represented in this list.
+    //
+    // For backups where ChunksMetadata#chunk_ordering_type = INLINE_LENGTHS:
+    // This field is unused. See ChunkOrderingType#INLINE_LENGTHS.
+    repeated int32 starts = 1 [packed = true];
+
+    // Checksum of plaintext content. (i.e., in correct order.)
+    //
+    // Each chunk also has a MAC, as generated by GCM, so this is NOT Mac-then-Encrypt, which has
+    // security implications. This is an additional checksum to verify that once the chunks have
+    // been reordered, that the file matches the expected plaintext. This prevents the device
+    // restoring garbage data in case of a mismatch between the ChunkOrdering and the backup blob.
+    optional bytes checksum = 2;
+}
+
+// Additional metadata about a backup blob that needs to be synced to the server. This is used on
+// restore to reconstruct the blob in its correct order. (The chunk order is randomized so as to
+// give the server less information about which parts of the backup are changing over time.) This
+// data structure is only ever uploaded to the server encrypted with a key unknown to the server.
+// Next tag : 6
+message ChunksMetadata {
+    // Cipher algorithm with which the chunk listing and chunks are encrypted.
+    optional CipherType cipher_type = 1;
+
+    // Defines the type of chunk order this metadata contains. If unspecified this backup file was
+    // created before INLINE_LENGTHS was supported, thus assume it is EXPLICIT_STARTS.
+    optional ChunkOrderingType chunk_ordering_type = 5
+    [default = CHUNK_ORDERING_TYPE_UNSPECIFIED];
+
+    // Encrypted bytes of ChunkOrdering
+    optional bytes chunk_ordering = 2;
+
+    // The type of algorithm used for the checksum of the plaintext. (See ChunkOrdering.) This is
+    // for forwards compatibility in case we change the algorithm in the future. For now, always
+    // SHA-256.
+    optional ChecksumType checksum_type = 3;
+
+    // This used to be the plaintext tertiary key. No longer used.
+    reserved 4;
+}
\ No newline at end of file
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 1257336..d33ea0c 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -157,6 +157,7 @@
     optional int32 rotation = 11;
     optional ScreenRotationAnimationProto screen_rotation_animation = 12;
     optional DisplayFramesProto display_frames = 13;
+    optional int32 surface_size = 14;
 }
 
 /* represents DisplayFrames */
@@ -211,6 +212,8 @@
     optional .android.graphics.RectProto bounds = 5;
     optional .android.graphics.RectProto temp_inset_bounds = 6;
     optional bool defer_removal = 7;
+    optional int32 surface_width = 8;
+    optional int32 surface_height = 9;
 }
 
 /* represents AppWindowToken */
diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto
index 25059be..c08d7ca 100644
--- a/core/proto/android/service/notification.proto
+++ b/core/proto/android/service/notification.proto
@@ -72,7 +72,8 @@
     option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
     optional int32 hint = 1;
-    repeated ManagedServiceInfoProto listeners = 2;
+    reserved 2; // ManagedServiceInfoProto listeners
+    repeated android.content.ComponentNameProto listener_components = 3;
 }
 
 message ManagedServiceInfoProto {
@@ -199,6 +200,10 @@
     optional string condition_id = 8;
     optional ConditionProto condition = 9;
     optional android.content.ComponentNameProto component = 10;
+    optional ZenPolicyProto zenPolicy = 11;
+
+    // Indicates whether this ZenRule has been modified after its initial creation
+    optional bool modified = 12 [ (android.privacy).dest = DEST_AUTOMATIC ];
 }
 
 // A dump from com.android.server.notification.ZenModeHelper.
@@ -211,3 +216,47 @@
     repeated android.content.ComponentNameProto suppressors = 4;
     optional android.app.PolicyProto policy = 5;
 }
+
+// An android.service.notification.ZenPolicy object
+message ZenPolicyProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    enum State {
+        STATE_UNSET = 0;
+        STATE_ALLOW = 1;
+        STATE_DISALLOW = 2;
+    }
+
+    // Notifications and sounds allowed/disallowed when DND is active
+    optional State reminders = 1;
+    optional State events = 2;
+    optional State messages = 3;
+    optional State calls = 4;
+    optional State repeat_callers = 5;
+    optional State alarms = 6;
+    optional State media = 7;
+    optional State system = 8;
+
+    // Visual effects allowed/disallowed for intercepted notifications when DND is active
+    optional State full_screen_intent = 9;
+    optional State lights = 10;
+    optional State peek = 11;
+    optional State status_bar = 12;
+    optional State badge= 13;
+    optional State ambient = 14;
+    optional State notification_list = 15;
+
+    enum Sender {
+        SENDER_UNSET = 0;
+        // Any sender is prioritized.
+        SENDER_ANY = 1;
+        // Saved contacts are prioritized.
+        SENDER_CONTACTS = 2;
+        // Only starred contacts are prioritized.
+        SENDER_STARRED = 3;
+        // No calls/messages are prioritized.
+        SENDER_NONE = 4;
+    }
+    optional Sender priority_calls = 16;
+    optional Sender priority_messages = 17;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 0be3403..85a52d5 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -615,6 +615,8 @@
     <protected-broadcast android:name="com.android.server.jobscheduler.FORCE_IDLE" />
     <protected-broadcast android:name="com.android.server.jobscheduler.UNFORCE_IDLE" />
 
+    <protected-broadcast android:name="android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL" />
+
     <!-- ====================================================================== -->
     <!--                          RUNTIME PERMISSIONS                           -->
     <!-- ====================================================================== -->
@@ -3054,6 +3056,18 @@
     <permission android:name="android.permission.MANAGE_DEVICE_ADMINS"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi Allows an app to reset the device password.
+         <p>Not for use by third-party applications.
+         @hide -->
+    <permission android:name="android.permission.RESET_PASSWORD"
+        android:protectionLevel="signature|privileged" />
+
+    <!-- @SystemApi Allows an app to lock the device.
+         <p>Not for use by third-party applications.
+         @hide -->
+    <permission android:name="android.permission.LOCK_DEVICE"
+        android:protectionLevel="signature|privileged" />
+
     <!-- @SystemApi Allows low-level access to setting the orientation (actually
          rotation) of the screen.
          <p>Not for use by third-party applications.
@@ -3756,6 +3770,10 @@
     <permission android:name="android.permission.USE_BIOMETRIC_INTERNAL"
         android:protectionLevel="signature" />
 
+    <!-- Allows the system to control the BiometricDialog (SystemUI). Reserved for the system. @hide -->
+    <permission android:name="android.permission.MANAGE_BIOMETRIC_DIALOG"
+        android:protectionLevel="signature" />
+
     <!-- Allows an app to reset face authentication attempt counter. Reserved for the system. @hide -->
     <permission android:name="android.permission.RESET_FACE_LOCKOUT"
         android:protectionLevel="signature" />
@@ -4112,7 +4130,7 @@
     <!-- Allows an application to directly open the "Open by default" page inside a package's
          Details screen.
          @hide <p>Not for use by third-party applications. -->
-    <permission android:name="android.permission.OPEN_APPLICATION_DETAILS_OPEN_BY_DEFAULT_PAGE"
+    <permission android:name="android.permission.OPEN_APP_OPEN_BY_DEFAULT_SETTINGS"
                 android:protectionLevel="signature" />
 
     <!-- Allows hidden API checks to be disabled when starting a process.
@@ -4120,6 +4138,16 @@
     <permission android:name="android.permission.DISABLE_HIDDEN_API_CHECKS"
                 android:protectionLevel="signature" />
 
+    <!-- @hide Permission that protects the
+        {@link android.provider.Telephony.Intents#ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL}
+        broadcast -->
+    <permission android:name="android.permission.MONITOR_DEFAULT_SMS_PACKAGE"
+        android:protectionLevel="signature" />
+
+    <!-- A subclass of {@link android.app.SmsAppService} must be protected with this permission. -->
+    <permission android:name="android.permission.BIND_SMS_APP_SERVICE"
+        android:protectionLevel="signature" />
+
     <application android:process="system"
                  android:persistent="true"
                  android:hasCode="false"
diff --git a/core/res/res/drawable/ic_ab_back_material_settings.xml b/core/res/res/drawable/ic_ab_back_material_settings.xml
index 7325a41..938e36d 100644
--- a/core/res/res/drawable/ic_ab_back_material_settings.xml
+++ b/core/res/res/drawable/ic_ab_back_material_settings.xml
@@ -18,11 +18,12 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="24dp"
         android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
         android:autoMirrored="true"
-        android:tint="?attr/colorControlNormal">
+        android:tint="?attr/colorControlNormal"
+        android:viewportHeight="24"
+        android:viewportWidth="24">
     <path
         android:fillColor="@color/white"
-        android:pathData="M20,11H7.62l4.88,-4.88a0.996,0.996 0,1 0,-1.41 -1.41l-6.94,6.94c-0.2,0.2 -0.2,0.51 0,0.71l6.94,6.94a0.996,0.996 0,1 0,1.41 -1.41L7.62,13H20c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1z"/>
+        android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8l8,8l1.41,-1.41L7.83,13H20V11z"/>
 </vector>
+
diff --git a/packages/SettingsLib/res/drawable/ic_info.xml b/core/res/res/drawable/ic_info.xml
similarity index 94%
rename from packages/SettingsLib/res/drawable/ic_info.xml
rename to core/res/res/drawable/ic_info.xml
index afe7e6b..f14c4b4 100644
--- a/packages/SettingsLib/res/drawable/ic_info.xml
+++ b/core/res/res/drawable/ic_info.xml
@@ -18,7 +18,7 @@
         android:height="24dp"
         android:viewportWidth="24"
         android:viewportHeight="24"
-        android:tint="?android:attr/colorAccent">
+        android:tint="?attr/colorControlNormal">
     <path
         android:fillColor="@android:color/white"
         android:pathData="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index c2c9254..5028150 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Probleem om Wi-Fi-oproepe by jou diensverskaffer te registreer: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Wi-Fi-oproep"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g>-Wi-Fi-oproepe"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN-oproep"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g>-WLAN-oproep"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g>-Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi-oproepe | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g>-VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Af"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Verkies Wi-Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Verkies mobiel"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Nie herken nie"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Vingerafdruk is gestaaf"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Gesig is gestaaf"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Gesig is gestaaf; druk asseblief bevestig"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Vingerafdrukhardeware is nie beskikbaar nie."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Vingerafdruk kan nie gestoor word nie. Verwyder asseblief \'n bestaande vingerafdruk."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Vingerafdrukuittelling is bereik. Probeer weer."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Gesiguittelling is bereik. Probeer weer."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Gesig kan nie geberg word nie."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Gesighandeling is gekanselleer."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Gesigstawing is deur gebruiker gekanselleer."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Te veel pogings. Probeer later weer."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Te veel pogings. Gesigstawingsensor is gedeaktiveer."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Probeer weer."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Kleurkorreksie"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Toeganklikheidskortpad het <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aangeskakel"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Toeganklikheidskortpad het <xliff:g id="SERVICE_NAME">%1$s</xliff:g> afgeskakel"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Gebruik weer toeganklikheidskortpad om die huidige toeganklikheidskenmerk te begin"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Kies \'n kenmerk om te gebruik wanneer jy op die Toeganklikheid-knoppie tik:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Raak en hou die Toeganklikheid-knoppie om kenmerke te verander."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Vergroting"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 45f962b..217d631 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"ከእርስዎ አገልግሎት አቅራቢ ጋር የWi‑Fi ጥሪን በማስመዝገብ ላይ ችግር፦ <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"የ%s Wi-Fi ጥሪ"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> የWi-Fi ጥሪ አደራረግ"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"የWLAN ጥሪ"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> የWLAN ጥሪ"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"የWiFi ጥሪ አደራረግ | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"ጠፍቷል"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi ተመርጧል"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"የተንቀሳቃሽ ስልክ ተመራጭ ነው"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"አልታወቀም"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"የጣት አሻራ ትክክለኛነት ተረጋግጧል"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"ፊት ተረጋግጧል"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"ፊት ተረጋግጧል፣ እባክዎ አረጋግጥን ይጫኑ"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"የጣት አሻራ ሃርድዌር አይገኝም።"</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"የጣት አሻራ ሊከማች አይችልም። እባክዎ አሁን ያለውን የጣት አሻራ ያስወግዱ።"</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"የጣት አሻራ ማብቂያ ጊዜ ደርሷል። እንደገና ይሞክሩ።"</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"የፊት ማብቂያ ጊዜ ደርሷል። እንደገና ይሞክሩ።"</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"ፊት ሊከማች አይችልም።"</string>
     <string name="face_error_canceled" msgid="283945501061931023">"የፊት ሥርዓተ ክወና ተሰርዟል።"</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"ፊትን ማረጋገጥ በተጠቃሚ ተሰርዟል።"</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"ከልክ በላይ ብዙ ሙከራዎች። በኋላ ላይ እንደገና ይሞክሩ።"</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"በጣም ብዙ ሙከራዎች። የፊት ማረጋገጫ ተሰናክሏል።"</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"እንደገና ይሞክሩ።"</string>
@@ -868,7 +875,7 @@
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"በፊት መክፈት።"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"በፒን መክፈት።"</string>
     <string name="keyguard_accessibility_sim_pin_unlock" msgid="9149698847116962307">"የሲም ፒን ክፈት።"</string>
-    <string name="keyguard_accessibility_sim_puk_unlock" msgid="9106899279724723341">"የሲም ፒዩኬ ክፈት።"</string>
+    <string name="keyguard_accessibility_sim_puk_unlock" msgid="9106899279724723341">"የሲም PUK ክፈት።"</string>
     <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"በይለፍ ቃል መክፈት።"</string>
     <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"የስርዓተ-ጥለት አካባቢ።"</string>
     <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"የማንሸራተቻ አካባቢ።"</string>
@@ -1582,7 +1589,7 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"ሲም ካርዱን በመክፈት ላይ…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"ትክክል ያልሆነ ፒን ኮድ።"</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"ከ4 እስከ 8 ቁጥሮች የያዘ ፒን ይተይቡ።"</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"የፒዩኬ ኮድ 8 ቁጥሮች ነው መሆን ያለበት።"</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"የPUK ኮድ 8 ቁጥሮች ነው መሆን ያለበት።"</string>
     <string name="kg_invalid_puk" msgid="3638289409676051243">"ትክክለኛውን የPUK ኮድ እንደገና ያስገቡ። ተደጋጋሚ ሙከራዎች ሲም ካርዱን እስከመጨረሻው ያሰናክሉታል።"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"ፒን ኮዶች አይገጣጠሙም"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"በጣም ብዙ የስርዓተ ጥለት ሙከራዎች"</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"የቀለም ማስተካከያ"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"የተደራሽነት አቋራጭ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ን አብርቶታል"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"የተደራሽነት አቋራጭ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ን አጥፍቶታል"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"አሁን ያለውን የተደራሽነት ባህሪ ለመጀመር እንደገና የተደራሽነት አቋራጭን ይጠቀሙ"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"የተደራሽነት አዝራርን መታ በሚያደርጉበት ጊዜ ጥቅም ላይ የሚውለውን ባህሪ ይምረጡ፦"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ባህሪያትን ለመለወጥ የተደራሽነት አዝራሩን ይንኩ እና ይያዙት።"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"ማጉላት"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index bbdea6a..c11279a 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -132,10 +132,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"‏حدثت مشكلة أثناء تسجيل الاتصال عبر Wi‑Fi باستخدام مشغِّل شبكة الجوّال: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"‏%s الاتصال عبر Wi-Fi"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"‏الاتصال عبر شبكة Wi-Fi التابعة لـ <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"‏مكالمة عبر شبكة WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"‏مكالمة عبر شبكة WLAN التابعة لـ <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"‏شبكة Wi-Fi التابعة لـ <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"‏الاتصال عبر شبكة WiFi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"‏شبكة VoWifi التابعة لـ <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"إيقاف"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"‏شبكة Wi-Fi مفضّلة"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"شبكة بيانات الجوال مفضَّلة"</string>
@@ -536,6 +540,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"لم يتم التعرف عليها."</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"تم مصادقة بصمة الإصبع"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"تمّت مصادقة الوجه"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"تمّت مصادقة الوجه، يُرجى الضغط على \"تأكيد\"."</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"جهاز بصمة الإصبع غير متاح."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"يتعذر تخزين بصمة الإصبع؛ يرجى إزالة إحدى البصمات المخزنة."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"تم بلوغ مهلة إدخال بصمة الإصبع. أعد المحاولة."</string>
@@ -572,6 +578,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"انتهت مهلة التعرُّف على الوجه. أعِد المحاولة."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"يتعذَّر حفظ الوجه."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"تمّ إلغاء عملية مصادقة الوجه."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"ألغَى المستخدم مصادقة الوجه."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"تمّ إجراء محاولات كثيرة. أعِد المحاولة لاحقًا."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"تمّ إجراء محاولات كثيرة. ميزة مصادقة الوجه متوقفة."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"يُرجى إعادة المحاولة."</string>
@@ -1712,6 +1719,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"تصحيح الألوان"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"شغَّل اختصار إمكانية الوصول خدمة <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"أوقف اختصار إمكانية الوصول خدمة <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"استخدِم اختصار إمكانية الوصول لبدء ميزة إمكانية الوصول الحالية."</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"يمكنك اختيار إحدى الميزات لاستخدامها عند النقر على زر إمكانية الوصول:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"لتغيير الميزات، يمكنك لمس زر \"إمكانية الوصول\" مع الاستمرار."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"التكبير"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 48d44b0..5a0a7ec 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"আপোনাৰ বাহকৰ ওচৰত ৱাই-ফাই কলিং সুবিধা পঞ্জীয়ন কৰাত সমস্যাৰ উদ্ভৱ হৈছে: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s ৱাই- ফাই কলিং"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> ৱাই- ফাই কলিং"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN কল"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN কল"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> ৱাই-ফাই"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"ৱাই- ফাই কলিং | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"অফ হৈ আছে"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"ৱাই-ফাইক অগ্ৰাধিকাৰ দিয়া হৈছে"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"ম\'বাইলক অগ্ৰাধিকাৰ দিয়া হৈছে"</string>
@@ -308,7 +312,7 @@
     <string name="permgrouprequest_visual" msgid="6907523945030290376">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ক আপোনাৰ ফট’ আৰু ভিডিঅ’সমূহ এক্সেছ কৰিবলৈ দিবনে?"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"ৱিণ্ড\' সমল বিচাৰি উলিয়াওক"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"আপুনি যোগাযোগ কৰি থকা ৱিণ্ড\'খনৰ সমল পৰীক্ষা কৰক।"</string>
-    <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"স্পৰ্শৰদ্বাৰা অন্বেষণ কৰাৰ সুবিধা অন কৰক"</string>
+    <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"স্পৰ্শৰ দ্বাৰা অন্বেষণ কৰাৰ সুবিধা অন কৰক"</string>
     <string name="capability_desc_canRequestTouchExploration" msgid="7543249041581408313">"টেপ কৰা বস্তুসমূহ ডাঙৰকৈ কোৱা হ\'ব আৰু আঙুলিৰ স্পৰ্শেৰে নিৰ্দেশ দি স্ক্ৰীণ অন্বেষণ কৰিব পাৰিব।"</string>
     <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"আপুনি লিখা পাঠ নিৰীক্ষণ কৰক"</string>
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"ক্ৰেডিট কাৰ্ডৰ নম্বৰ আৰু পাছৱৰ্ডৰ দৰে ব্যক্তিগত ডেটা অন্তৰ্ভুক্ত হ\'ব পাৰে।"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"চিনাক্ত কৰিব পৰা নাই"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"ফিংগাৰপ্ৰিণ্টৰ সত্যাপন কৰা হ’ল"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"মুখমণ্ডলৰ বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ কৰা হ\'ল"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"মুখমণ্ডলৰ বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ কৰা হ\'ল, অনুগ্ৰহ কৰি ‘নিশ্চিত কৰক’ বুটামটো টিপক"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ফিংগাৰপ্ৰিণ্ট হাৰ্ডৱেৰ নাই।"</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"ফিংগাৰপ্ৰিণ্ট সঞ্চয় কৰিব পৰা নগ\'ল। পূর্বে সঞ্চিত ফিংগাৰপ্ৰিণ্ট এটা আঁতৰাওক।"</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"ফিংগাৰপ্ৰিণ্ট গ্ৰহণৰ সময়সীমা উকলি গৈছে। আকৌ চেষ্টা কৰক।"</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"মুখমণ্ডল গ্ৰহণৰ সময়সীমা উকলি গৈছে। আকৌ চেষ্টা কৰক।"</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"মুখমণ্ডল সঞ্চয় কৰিব নোৱাৰি।"</string>
     <string name="face_error_canceled" msgid="283945501061931023">"মুখমণ্ডলৰ প্ৰক্ৰিয়া বাতিল কৰা হ’ল।"</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"ব্যৱহাৰকাৰীয়ে মুখমণ্ডলৰ বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ বাতিল কৰিছে।"</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"অত্যধিক ভুল প্ৰয়াস। কিছুসময়ৰ পাছত আকৌ চেষ্টা কৰক।"</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"অত্যধিক প্ৰয়াস। মুখমণ্ডলৰ জৰিয়তে সত্যাপন অক্ষম কৰা হ’ল।"</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"আকৌ চেষ্টা কৰক।"</string>
@@ -1404,7 +1411,7 @@
     <string name="forward_intent_to_work" msgid="621480743856004612">"আপুনি আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইলৰ ভিতৰত এই এপটো ব্যৱহাৰ কৰি আছে"</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"ইনপুট পদ্ধতি"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"ছিংক"</string>
-    <string name="accessibility_binding_label" msgid="4148120742096474641">"সাধ্য় সুবিধাসমূহ"</string>
+    <string name="accessibility_binding_label" msgid="4148120742096474641">"সাধ্য সুবিধাসমূহ"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"ৱালপেপাৰ"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"ৱালপেপাৰ সলনি কৰক"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"জাননী নিৰীক্ষক"</string>
@@ -1617,6 +1624,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"ৰং শুধৰণী"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"দিব্যাংগসকলৰ সুবিধাৰ শ্বৰ্টকাটটোৱে <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ক অন কৰিছে"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"দিব্যাংগসকলৰ সুবিধাৰ শ্বৰ্টকাটটোৱে <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ক অফ কৰিছে"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"বর্তমানৰ সাধ্য সুবিধাসমূহৰ আৰম্ভ কৰিবলৈ সাধ্য সুবিধাসমূহৰ শ্বৰ্টকাট পুনৰ ব্যৱহাৰ কৰক"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"আপুনি দিব্যাংগসকলৰ সুবিধাৰ বুটামটো টিপিলে ব্যৱহাৰ কৰিবলগীয়া কোনো সুবিধা বাছক:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"সুবিধাসমূহ সলনি কৰিবলৈ দিব্যাংগসকলৰ সুবিধাৰ বুটামটো স্পৰ্শ কৰি থাকক।"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"বিবৰ্ধন"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 44bcd56..af65bbb 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Operatorla Wi‑Fi zənglərini qeydə alarkən xəta baş verdi: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Wi-Fi Zəngi"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi Zəngi"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN Zəngi"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN Zəngi"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"WiFi Zəngi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Deaktiv"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi tərcih edilir"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Mobil tərcih"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Tanınmır"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Barmaq izi doğrulandı"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Üz doğrulandı"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Üz təsdiq edildi, təsdiq düyməsinə basın"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Barmaq izi üçün avadanlıq yoxdur."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Barmaq izi saxlana bilməz. Lütfən, mövcud barmaq izini silin."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Barmaq izinin vaxtı başa çatdı. Yenidən cəhd edin."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Üz proqramı taymerinin vaxtı bitdi. Yenidən cəhd edin."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Üz bərpa edilmədi."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Üz əməliyyatı ləğv edildi."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Üz dorğulaması istifadəçi tərəfindən ləğv edildi."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Həddindən çox cəhd. Sonraya saxlayın."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Həddindən çox cəhd. Üz identifikasiyası deaktiv edildi."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Yenidən cəhd edin."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Rəng korreksiyası"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Əlçatımlıq Qısayolu <xliff:g id="SERVICE_NAME">%1$s</xliff:g> xidmətini aktiv etdi"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Əlçatımlıq Qısayolu <xliff:g id="SERVICE_NAME">%1$s</xliff:g> xidmətini deaktiv etdi"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Cari əlçatımlılıq funksiyasını yenidən başlatmaq üçün Əlçatımlılıq Qısayolundan istifadə edin"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Əlçatımlılıq düyməsinə kliklədikdə istifadə etmək üçün funksiya seçin:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Funksiyaları dəyişmək üçün Əlçatımlılıq düyməsinə basıb saxlayın."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Böyütmə"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 260f63e..805082a 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -129,10 +129,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Problem u vezi sa registrovanjem pozivanja preko Wi‑Fi-ja kod mobilnog operatera: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"Wi-Fi pozivanje preko operatera %s"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> pozivanje preko Wi-Fi-ja"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN poziv"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN poziv"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Pozivanje preko Wi-Fi-ja | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Isključeno"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Prednost ima Wi-Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Želim mobilne podatke"</string>
@@ -527,6 +531,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Nije prepoznato"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Otisak prsta je potvrđen"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Lice je potvrđeno"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Lice je potvrđeno. Pritisnite Potvrdi"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardver za otiske prstiju nije dostupan."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Nije moguće sačuvati otisak prsta. Uklonite neki od postojećih otisaka prstiju."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Vremensko ograničenje za otisak prsta je isteklo. Probajte ponovo."</string>
@@ -563,6 +569,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Isteklo je vreme za proveru lica. Probajte ponovo."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Nije moguće sačuvati lice."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Obrada lica je otkazana."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Korisnik je otkazao potvrdu lica."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Previše pokušaja. Probajte ponovo kasnije."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Više pokušaja. Potvrda identiteta je onemogućena."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Probajte ponovo."</string>
@@ -1640,6 +1647,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Korekcija boja"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Prečica za pristupačnost je uključila uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Prečica za pristupačnost je isključila uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Upotrebite ponovo prečicu za pristupačnost da biste pokrenuli aktuelnu funkciju pristupačnosti"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Izaberite funkciju koja će se koristiti kada dodirnete dugme za pristupačnost:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Pritisnite i zadržite dugme za pristupačnost da biste menjali funkcije."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Uvećanje"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 3d46662..7692220 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -130,10 +130,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Памылка падключэння Wi‑Fi-тэлефаніі ў вашага аператара: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"Wi-Fi-тэлефанія %s"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Wi-Fi-тэлефанія ад <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Выклік праз WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Выклік праз WLAN ад <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi ад <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi-тэлефанія | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWi-Fi ад <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Выкл."</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Прыярытэт Wi-Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Прыярытэт мабільнай сеткі"</string>
@@ -530,6 +534,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Не распазнана"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Адбітак пальца распазнаны"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Твар распазнаны"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Твар распазнаны. Націсніце, каб пацвердзіць"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Апаратныя сродкі адбіткаў пальцаў недаступныя."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Адбіткі пальцаў нельга захаваць. Выдаліце існы адбітак."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Час чакання адбіткаў пальцаў выйшаў. Паспрабуйце яшчэ раз."</string>
@@ -566,6 +572,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Час чакання твару выйшаў. Паўтарыце спробу."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Не ўдалося захаваць твар."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Распазнаванне твару скасавана."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Распазнаванне твару скасавана карыстальнікам."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Занадта шмат спроб. Паўтарыце спробу пазней."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Занадта шмат спроб. Аўтэнтыфікацыя твару адключана"</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Паўтарыце спробу."</string>
@@ -1664,6 +1671,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Карэкцыя колеру"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> быў уключаны з дапамогай камбінацыі хуткага доступу для спецыяльных магчымасцей"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> быў адключаны з дапамогай камбінацыі хуткага доступу для спецыяльных магчымасцей"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Каб запусціць функцыю спецыяльных магчымасцей, паўторна скарыстайце ярлык спецыяльных магчымасцей"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Выберыце функцыю для выкарыстання пры націску кнопкі \"Спецыяльныя магчымасці\":"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Каб змяняць функцыі, краніце і ўтрымлівайце кнопку \"Спецыяльныя магчымасці\"."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Павелічэнне"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index e9ecba6..33c4898 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"При регистрирането на функцията за обаждания през Wi-Fi с оператора ви възникна грешка: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s – обаждания през Wi-Fi"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Обаждания през Wi-Fi от <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Обаждане през WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Обаждане през WLAN от <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi от <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Обаждания през Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWi-Fi от <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Изключено"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Предпочита се Wi-Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Предпочитат се мобилни данни"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Не е разпознато"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Отпечатъкът е удостоверен"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Лицето е удостоверено"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Лицето е удостоверено. Моля, натиснете „Потвърждаване“"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Хардуерът за отпечатъци не е налице."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Отпечатъкът не може да бъде съхранен. Моля, премахнете съществуващ."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Времето за изчакване за отпечатък изтече. Опитайте отново."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Времето за изчакване изтече. Опитайте отново."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Лицето не може да бъде съхранено."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Операцията с лице е анулирана."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Удостоверяв. на лицето е анулирано от потребителя."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Твърде много опити. Опитайте отново по-късно."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Твърде много опити. Удост. с лице е деактивирано."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Опитайте отново."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Коригиране на цветовете"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Прекият път за достъпност включи <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Прекият път за достъпност изключи <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Използвайте отново прекия път към функцията за достъпност, за да стартирате текущата"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Изберете функция, която да използвате, когато докоснете бутона за достъпност:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"За да промените функции, докоснете и задръжте бутона за достъпност."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ниво на мащаба"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 4ece21b..f0787b4 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"পরিষেবা প্রদানকারীতে ওয়াই-ফাই কলিং রেজিস্টার করতে সমস্যা হয়েছে: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s ওয়াই-ফাই কলিং"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> ওয়াই-ফাই কলিং"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN কল"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN কল"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> ওয়াই-ফাই"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"ওয়াই-ফাই কলিং | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"বন্ধ আছে"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"পছন্দের ওয়াই-ফাই"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"পছন্দের মোবাইল"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"স্বীকৃত নয়"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"আঙ্গুলের ছাপ যাচাই করা হয়েছে"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"ফেস যাচাই করা হয়েছে"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"ফেস যাচাই করা হয়েছে, \'কনফার্ম করুন\' বোতাম প্রেস করুন"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"আঙ্গুলের ছাপ নেওয়ার হার্ডওয়্যার অনুপলব্ধ৷"</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"আঙ্গুলের ছাপ সংরক্ষণ করা যাবে না৷ অনুগ্রহ করে একটি বিদ্যমান আঙ্গুলের ছাপ সরান৷"</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"আঙ্গুলের ছাপ নেওয়ার সময়সীমা শেষ হযেছে৷ আবার চেষ্টা করুন৷"</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"ফেসের ছাপ নেওয়ার সময়সীমা শেষ৷ আবার চেষ্টা করুন৷"</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"ফেস স্টোর করা যাবে না।"</string>
     <string name="face_error_canceled" msgid="283945501061931023">"ফেস অপারেশন বাতিল করা হয়েছে৷"</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"ফেস যাচাইকরণ ব্যবহারকারীর দ্বারা বাতিল করা হয়েছে।"</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"অনেকবার চেষ্টা করা হয়েছে। পরে আবার চেষ্টা করুন।"</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"অনেকবার চেষ্টা করা হয়েছে৷ ফেস যাচাইকরণ বন্ধ আছে।"</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"আবার চেষ্টা করুন।"</string>
@@ -1617,6 +1624,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"রঙ সংশোধন"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"অ্যাক্সেসযোগ্যতা শর্টকাট <xliff:g id="SERVICE_NAME">%1$s</xliff:g> কে চালু করেছে"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"অ্যাক্সেসযোগ্যতা শর্টকাট <xliff:g id="SERVICE_NAME">%1$s</xliff:g> কে বন্ধ করেছে"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"বর্তমান অ্যাক্সেসিবিলিটি বৈশিষ্ট্য শুরু করার জন্য অ্যাক্সেসিবিলিটি শর্টকাটটি আবার ব্যবহার করুন"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"অ্যাক্সেসযোগ্যতা বোতামের সাহায্যে যে বৈশিষ্ট্যটি নিয়ন্ত্রণ করতে চান, সেটি বেছে নিন:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"বৈশিষ্ট্যগুলি পরিবর্তন করতে অ্যাক্সেসযোগ্যতা বোতামটি ট্যাপ করে ধরে রাখুন।"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"বড় করে দেখা"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 918ecf9..e210d90e 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -129,10 +129,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Došlo je do problema prilikom registracije pozivanja putem WiFi mreže kod vašeg operatera: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"Pozivanje putem WiFi-ja preko operatera %s"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Pozivanje putem WiFi-ja"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN poziv"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN poziv"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> WiFi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Pozivanje putem WiFi-ja | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Isključeno"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Preferira se WiFi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Preferira se mobilna mreža"</string>
@@ -527,6 +531,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Nije prepoznato"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Otisak prsta je potvrđen"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Lice je provjereno"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Lice je provjereno, pritisnite dugme za potvrdu"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardver za otisak prsta nije dostupan."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Otisak prsta se ne može pohraniti. Uklonite postojeći otisak prsta."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Vrijeme za prepoznavanje otiska prsta je isteklo. Pokušajte ponovo."</string>
@@ -563,6 +569,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Vrijeme za prepoznavanje lica je isteklo. Pokušajte ponovo."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Nije moguće pohraniti lice."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Prepoznavanje lica je otkazano."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Korisnik je otkazao provjeru lica."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Previše pokušaja. Pokušajte ponovo kasnije."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Previše pokušaja. Autentifikacija lica onemogućena."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Pokušajte ponovo."</string>
@@ -1642,6 +1649,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Ispravka boja"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Prečica za pristupačnost je uključila uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Prečica za pristupačnost je isključila uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Ponovo koristite Prečicu za pristupačnost da započnete trenutnu funkciju pristupačnosti"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Odaberite funkciju koja će se koristiti kada dodirnete dugme Pristupačnost:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Da promijenite funkcije, dodirnite i držite dugme Pristupačnost."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Uvećanje"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index f6c46ba..b1d4994 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Hi ha hagut un problema en registrar les trucades per Wi-Fi amb el teu operador de telefonia mòbil: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"Trucades per Wi-Fi %s"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Trucades per Wi‑Fi (<xliff:g id="SPN">%s</xliff:g>)"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Trucada per WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Trucada per WLAN (<xliff:g id="SPN">%s</xliff:g>)"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi‑Fi (<xliff:g id="SPN">%s</xliff:g>)"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Trucades per Wi‑Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi (<xliff:g id="SPN">%s</xliff:g>)"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Desactivat"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Preferència per la Wi-Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Preferència per dades mòbils"</string>
@@ -295,7 +299,7 @@
     <string name="permgroupdesc_calllog" msgid="3006237336748283775">"llegir i editar el registre de trucades del telèfon"</string>
     <string name="permgrouprequest_calllog" msgid="8487355309583773267">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; accedeixi als registres de trucades del telèfon?"</string>
     <string name="permgrouplab_phone" msgid="5229115638567440675">"Telèfon"</string>
-    <string name="permgroupdesc_phone" msgid="6234224354060641055">"fer i gestionar trucades telefòniques"</string>
+    <string name="permgroupdesc_phone" msgid="6234224354060641055">"fer i gestionar trucades"</string>
     <string name="permgrouprequest_phone" msgid="9166979577750581037">"Vols permetre que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; faci trucades i les gestioni?"</string>
     <string name="permgrouplab_sensors" msgid="416037179223226722">"Sensors corporals"</string>
     <string name="permgroupdesc_sensors" msgid="7147968539346634043">"accedir a les dades del sensor sobre els signes vitals"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"No s\'ha reconegut"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"L\'empremta digital s\'ha autenticat"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Cara autenticada"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Cara autenticada; prem el botó per confirmar"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"El maquinari per a empremtes digitals no està disponible."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"L\'empremta digital no es pot desar. Suprimeix-ne una."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"S\'ha esgotat el temps d\'espera per a l\'empremta digital. Torna-ho a provar."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"S\'ha esgotat el temps d\'espera. Torna-ho a provar."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"La cara no es pot desar."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"S\'ha cancel·lat el reconeixement facial."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Autenticació facial cancel·lada per l\'usuari."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Massa intents. Torna-ho a provar més tard."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Massa intents. Autenticació facial desactivada."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Torna-ho a provar."</string>
@@ -804,8 +811,8 @@
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"Falta la targeta SIM o no es pot llegir. Insereix-ne una."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Targeta SIM no utilitzable."</string>
     <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"La targeta SIM està desactivada permanentment.\n Contacta amb el teu proveïdor de serveis sense fil per obtenir-ne una altra."</string>
-    <string name="lockscreen_transport_prev_description" msgid="6300840251218161534">"Ruta anterior"</string>
-    <string name="lockscreen_transport_next_description" msgid="573285210424377338">"Ruta següent"</string>
+    <string name="lockscreen_transport_prev_description" msgid="6300840251218161534">"Pista anterior"</string>
+    <string name="lockscreen_transport_next_description" msgid="573285210424377338">"Pista següent"</string>
     <string name="lockscreen_transport_pause_description" msgid="3980308465056173363">"Posa en pausa"</string>
     <string name="lockscreen_transport_play_description" msgid="1901258823643886401">"Reprodueix"</string>
     <string name="lockscreen_transport_stop_description" msgid="5907083260651210034">"Atura"</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Correcció del color"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"La drecera d\'accessibilitat ha activat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"La drecera d\'accessibilitat ha desactivat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Torna a utilitzar la drecera d\'accessibilitat per iniciar la funció d\'accessibilitat actual"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Tria la funció que s\'utilitzarà quan toquis el botó Accessibilitat:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Per canviar les funcions, toca i mantén premut el botó Accessibilitat."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ampliació"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index e882f42..a537d6d 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -130,10 +130,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Při registraci volání přes Wi-Fi u operátora <xliff:g id="CODE">%1$s</xliff:g> došlo k chybě"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"Volání přes Wi-Fi: %s"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g>: volání přes Wi-Fi"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Volání přes WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g>: volání přes WLAN"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g>: Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Volání přes Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g>: VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Vypnuto"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Preferována síť W-Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Preferována mobilní data"</string>
@@ -530,6 +534,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Nerozpoznáno"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Otisk byl ověřen"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Obličej byl ověřen"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Obličej byl ověřen, stiskněte tlačítko pro potvrzení"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Není k dispozici hardware ke snímání otisků prstů."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Otisk prstu nelze uložit. Odstraňte existující otisk prstu."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Časový limit sejmutí otisku prstu vypršel. Zkuste to znovu."</string>
@@ -566,6 +572,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Limit ověření obličeje vypršel. Zkuste to znovu."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Obličej nelze uložit."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Operace snímání obličeje byla zrušena."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Ověření obličeje bylo zrušeno uživatelem."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Příliš mnoho pokusů. Zkuste to později."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Příliš mnoho pokusů. Ověření obličeje je zakázáno."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Zkuste to znovu."</string>
@@ -1664,6 +1671,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Oprava barev"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Zkratka přístupnosti zapnula službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Zkratka přístupnosti vypnula službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Znovu použijte zkratku přístupnosti, čímž spustíte aktuální funkci pro usnadnění přístupu"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Určete, jakou funkci aktivujete klepnutím na tlačítko Přístupnost:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Chcete-li vybrat jinou funkci, podržte tlačítko Přístupnost."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Zvětšení"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 9a793a8..28c08b1 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Der opstod et problem under registrering af Wi-Fi-opkald hos dit mobilselskab: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Wi-Fi-opkald"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Wi-Fi-opkald via <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN-opkald"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"WLAN-opkald via <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi via <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi-opkald | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi via <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Fra"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"WiFi-netværk er foretrukket"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Mobildata foretrækkes"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Ikke genkendt"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingeraftrykket blev godkendt"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Ansigtet er godkendt"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Ansigtet er godkendt. Tryk på Bekræft."</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardwaren til fingeraftryk er ikke tilgængelig."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingeraftrykket kan ikke gemmes. Fjern et eksisterende fingeraftryk."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Registrering af fingeraftryk fik timeout. Prøv igen."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Ansigtsgenkendelse fik timeout. Prøv igen."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Ansigtet kan ikke gemmes."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Ansigtshandlingen blev annulleret."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Ansigtsgodkendelsen blev annulleret af brugeren."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Du har prøvet for mange gange. Prøv igen senere."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"For mange forsøg – Ansigtsgenkendelse deaktiveret."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Prøv igen."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Korriger farve"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Genvejen til hjælpefunktioner aktiverede <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Genvejen til hjælpefunktioner deaktiverede <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Brug Genvej til hjælpefunktioner for at starte den aktuelle hjælpefunktion"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Vælg, hvilken funktion du vil bruge, når du trykker på knappen Hjælpefunktioner:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Tryk på knappen Hjælpefunktioner, og hold fingeren nede for at skifte funktioner."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Forstørrelse"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 8eb0eb8..4a2efbd 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Probleme beim Registrieren der WLAN-Telefonie bei deinem Mobilfunkanbieter: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s WLAN-Telefonie"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> WLAN-Telefonie"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN-Anruf"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN-Anruf"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> WLAN"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"WLAN-Telefonie | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWLAN"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Aus"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"WLAN bevorzugt"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Mobilverbindung bevorzugt"</string>
@@ -150,7 +154,7 @@
     <string name="httpErrorAuth" msgid="1435065629438044534">"Bei der Authentifizierung ist ein Fehler aufgetreten."</string>
     <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Authentifizierung via Proxyserver ist fehlgeschlagen."</string>
     <string name="httpErrorConnect" msgid="8714273236364640549">"Verbindung zum Server konnte nicht hergestellt werden."</string>
-    <string name="httpErrorIO" msgid="2340558197489302188">"Kommunikation mit dem Server konnte nicht hergestellt werden. Bitte versuche es später erneut."</string>
+    <string name="httpErrorIO" msgid="2340558197489302188">"Kommunikation mit dem Server konnte nicht hergestellt werden. Bitte versuche es später noch einmal."</string>
     <string name="httpErrorTimeout" msgid="4743403703762883954">"Zeitüberschreitung bei Serververbindung."</string>
     <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Die Seite enthält zu viele Server-Redirects."</string>
     <string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"Das Protokoll wird nicht unterstützt."</string>
@@ -158,7 +162,7 @@
     <string name="httpErrorBadUrl" msgid="3636929722728881972">"Die Seite kann nicht geöffnet werden, weil die URL ungültig ist."</string>
     <string name="httpErrorFile" msgid="2170788515052558676">"Auf die Datei konnte nicht zugegriffen werden."</string>
     <string name="httpErrorFileNotFound" msgid="6203856612042655084">"Die angeforderte Datei wurde nicht gefunden."</string>
-    <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Es werden zurzeit zu viele Anfragen verarbeitet. Versuche es später erneut."</string>
+    <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Es werden zurzeit zu viele Anfragen verarbeitet. Bitte versuche es später noch einmal."</string>
     <string name="notification_title" msgid="8967710025036163822">"Fehler bei Anmeldung für <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
     <string name="contentServiceSync" msgid="8353523060269335667">"Synchronisierung"</string>
     <string name="contentServiceSyncNotificationTitle" msgid="7036196943673524858">"Synchronisierung nicht möglich"</string>
@@ -515,23 +519,25 @@
     <string name="permlab_mediaLocation" msgid="8675148183726247864">"Standorte aus meiner Mediensammlung abrufen"</string>
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Ermöglicht der App, Standorte aus deiner Mediensammlung abzurufen."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrische Hardware nicht verfügbar"</string>
-    <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Fingerabdruck teilweise erkannt. Versuche es erneut."</string>
-    <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Fingerabdruck konnte nicht verarbeitet werden. Versuche es erneut."</string>
-    <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Fingerabdrucksensor ist verschmutzt. Reinige ihn und versuche es erneut."</string>
-    <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"Finger zu schnell bewegt. Versuche es erneut."</string>
-    <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Finger zu langsam bewegt. Versuche es erneut."</string>
+    <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Fingerabdruck teilweise erkannt. Bitte versuche es noch einmal."</string>
+    <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Fingerabdruck konnte nicht verarbeitet werden. Bitte versuche es noch einmal."</string>
+    <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Fingerabdrucksensor ist verschmutzt. Reinige ihn und versuche es noch einmal."</string>
+    <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"Finger zu schnell bewegt. Bitte versuche es noch einmal."</string>
+    <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Finger zu langsam bewegt. Bitte versuche es noch einmal."</string>
   <string-array name="fingerprint_acquired_vendor">
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Nicht erkannt"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingerabdruck wurde authentifiziert"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Gesicht authentifiziert"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Gesicht authentifiziert, bitte bestätigen"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Fingerabdruckhardware nicht verfügbar"</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingerabdruck kann nicht gespeichert werden. Entferne einen vorhandenen Fingerabdruck."</string>
-    <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Zeitüberschreitung für Fingerabdruck. Versuche es erneut."</string>
+    <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Zeitüberschreitung für Fingerabdruck. Bitte versuche es noch einmal."</string>
     <string name="fingerprint_error_canceled" msgid="4402024612660774395">"Fingerabdruckvorgang abgebrochen"</string>
     <string name="fingerprint_error_user_canceled" msgid="7999639584615291494">"Vorgang der Fingerabdruckauthentifizierung vom Nutzer abgebrochen."</string>
-    <string name="fingerprint_error_lockout" msgid="5536934748136933450">"Zu viele Versuche. Versuche es später erneut."</string>
+    <string name="fingerprint_error_lockout" msgid="5536934748136933450">"Zu viele Versuche. Bitte versuche es später noch einmal."</string>
     <string name="fingerprint_error_lockout_permanent" msgid="5033251797919508137">"Zu viele Versuche. Der Fingerabdrucksensor wurde deaktiviert."</string>
-    <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Bitte versuche es erneut."</string>
+    <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Bitte versuche es noch einmal."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="7654382120628334248">"Keine Fingerabdrücke erfasst."</string>
     <string name="fingerprint_error_hw_not_present" msgid="5729436878065119329">"Dieses Gerät hat keinen Fingerabdrucksensor"</string>
     <string name="fingerprint_name_template" msgid="5870957565512716938">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Zeitüberschreitung für Gesicht. Versuch es erneut."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Gesicht kann nicht gespeichert werden."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Gesichtserkennung abgebrochen."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Gesichtsauthentifizierung vom Nutzer abgebrochen."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Zu viele Versuche. Versuch es später noch einmal."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Zu viele Versuche. Gesichtserkennung deaktiviert."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Versuch es noch einmal."</string>
@@ -1085,7 +1092,7 @@
     <string name="view_flight" msgid="7691640491425680214">"Verfolgen"</string>
     <string name="view_flight_desc" msgid="3876322502674253506">"Ausgewählten Flug verfolgen"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Der Speicherplatz wird knapp"</string>
-    <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Einige Systemfunktionen funktionieren möglicherweise nicht."</string>
+    <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Einige Systemfunktionen funktionieren eventuell nicht."</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Der Speicherplatz reicht nicht für das System aus. Stelle sicher, dass 250 MB freier Speicherplatz vorhanden sind, und starte das Gerät dann neu."</string>
     <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> wird ausgeführt"</string>
     <string name="app_running_notification_text" msgid="1197581823314971177">"Für weitere Informationen oder zum Beenden der App tippen."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Farbkorrektur"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> wurde durch die Bedienungshilfenverknüpfung aktiviert"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> wurde durch die Bedienungshilfenverknüpfung deaktiviert"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Verwende noch einmal die Verknüpfung für Bedienungshilfen, um die aktuelle Bedienungshilfe zu starten."</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Wähle eine Funktion aus, die verwendet wird, wenn du auf die Schaltfläche für die Bedienungshilfen tippst:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Um die Funktionen zu ändern, halte die Schaltfläche für die Bedienungshilfen gedrückt."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Vergrößerung"</string>
@@ -1723,7 +1731,7 @@
     <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Neue PIN"</string>
     <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Neue PIN bestätigen"</string>
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"PIN für das Ändern von Einschränkungen erstellen"</string>
-    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Die PINs stimmen nicht überein. Bitte versuche es erneut."</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Die PINs stimmen nicht überein. Bitte versuche es noch einmal."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Die PIN ist zu kurz. Sie muss mindestens 4 Ziffern umfassen."</string>
     <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
       <item quantity="other">In <xliff:g id="COUNT">%d</xliff:g> Sek. wiederholen</item>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 3a50f9e..04b9749 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Παρουσιάστηκε πρόβλημα με την εγγραφή της κλήσης Wi‑Fi με την εταιρεία κινητής τηλεφωνίας: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Κλήση Wi-Fi"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Κλήση Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Κλήση μέσω WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Κλήση μέσω WLAN <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Κλήση Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Ανενεργό"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Προτίμηση Wi-Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Προτίμηση δικτύου κινητής τηλεφωνίας"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Δεν αναγνωρίστηκε"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Η ταυτότητα του δακτυλικού αποτυπώματος ελέγχθηκε"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Έγινε έλεγχος ταυτότητας προσώπου"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Έγινε έλεγχος ταυτότητας προσώπου, πατήστε \"Επιβεβαίωση\""</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Ο εξοπλισμός μοναδικού χαρακτηριστικού δεν είναι διαθέσιμος."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Δεν είναι δυνατή η αποθήκευση μοναδικού χαρακτηριστικού. Καταργήστε το υπάρχον μοναδικό χαρακτηριστικό."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Λήξη χρονικού ορίου μοναδικού χαρακτηριστικού. Δοκιμάστε ξανά."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Λήξη χρονικού ορίου προσώπου. Δοκιμάστε ξανά."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Δεν είναι δυνατή η αποθήκευση του προσώπου."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Η ενέργεια προσώπου ακυρώθηκε."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Ο έλεγχος ταυτότητας προσώπου ακυρώθηκε από τον χρήστη."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Πάρα πολλές προσπάθειες. Δοκιμάστε ξανά αργότερα."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Πολλές προσπάθειες. Αποτυχία ελέγ. ταυτ. προσώπου."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Δοκιμάστε ξανά."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Διόρθωση χρωμάτων"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Η συντόμευση προσβασιμότητας ενεργοποίησε την υπηρεσία <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Η συντόμευση προσβασιμότητας απενεργοποίησε την υπηρεσία <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Χρησιμοποιήστε τη Συντόμευση προσβασιμότητας ξανά, για να ξεκινήσετε την τρέχουσα λειτουργία προσβασιμότητας"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Επιλέξτε μια λειτουργία που θα χρησιμοποιείται κατά το πάτημα του κουμπιού \"Προσβασιμότητα\"."</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Για να αλλάξετε λειτουργίες, αγγίξτε παρατεταμένα το κουμπί \"Προσβασιμότητα\"."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Μεγιστοποίηση"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 04b20ba..8592355 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Issue registering Wi‑Fi calling with your operator: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Wi-Fi Calling"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi Calling"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN call"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN Call"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi Calling | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Off"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi preferred"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Mobile preferred"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Not recognised"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingerprint authenticated"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Face authenticated"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Face authenticated. Please press confirm"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Fingerprint hardware not available."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingerprint can\'t be stored. Please remove an existing fingerprint."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Fingerprint timeout reached. Try again."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Face time out reached. Try again."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Face can’t be stored."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Face operation cancelled."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Face authentication cancelled by user."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Too many attempts. Try again later."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Too many attempts. Facial authentication disabled."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Try again."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Colour Correction"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> off"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Use Accessibility Shortcut again to start the current accessibility feature"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Choose a feature to use when you tap the Accessibility button:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"To change features, touch &amp; hold the Accessibility button."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Magnification"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index c1ca0c4..1e075f8 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Issue registering Wi‑Fi calling with your operator: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Wi-Fi Calling"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi Calling"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN call"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN Call"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi Calling | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Off"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi preferred"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Mobile preferred"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Not recognised"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingerprint authenticated"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Face authenticated"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Face authenticated. Please press confirm"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Fingerprint hardware not available."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingerprint can\'t be stored. Please remove an existing fingerprint."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Fingerprint timeout reached. Try again."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Face time out reached. Try again."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Face can’t be stored."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Face operation cancelled."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Face authentication cancelled by user."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Too many attempts. Try again later."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Too many attempts. Facial authentication disabled."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Try again."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Colour Correction"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> off"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Use Accessibility Shortcut again to start the current accessibility feature"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Choose a feature to use when you tap the Accessibility button:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"To change features, touch &amp; hold the Accessibility button."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Magnification"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 04b20ba..8592355 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Issue registering Wi‑Fi calling with your operator: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Wi-Fi Calling"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi Calling"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN call"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN Call"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi Calling | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Off"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi preferred"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Mobile preferred"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Not recognised"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingerprint authenticated"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Face authenticated"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Face authenticated. Please press confirm"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Fingerprint hardware not available."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingerprint can\'t be stored. Please remove an existing fingerprint."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Fingerprint timeout reached. Try again."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Face time out reached. Try again."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Face can’t be stored."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Face operation cancelled."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Face authentication cancelled by user."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Too many attempts. Try again later."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Too many attempts. Facial authentication disabled."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Try again."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Colour Correction"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> off"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Use Accessibility Shortcut again to start the current accessibility feature"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Choose a feature to use when you tap the Accessibility button:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"To change features, touch &amp; hold the Accessibility button."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Magnification"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 04b20ba..8592355 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Issue registering Wi‑Fi calling with your operator: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Wi-Fi Calling"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi Calling"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN call"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN Call"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi Calling | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Off"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi preferred"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Mobile preferred"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Not recognised"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingerprint authenticated"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Face authenticated"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Face authenticated. Please press confirm"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Fingerprint hardware not available."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingerprint can\'t be stored. Please remove an existing fingerprint."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Fingerprint timeout reached. Try again."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Face time out reached. Try again."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Face can’t be stored."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Face operation cancelled."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Face authentication cancelled by user."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Too many attempts. Try again later."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Too many attempts. Facial authentication disabled."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Try again."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Colour Correction"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> off"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Use Accessibility Shortcut again to start the current accessibility feature"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Choose a feature to use when you tap the Accessibility button:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"To change features, touch &amp; hold the Accessibility button."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Magnification"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 4add775..9138098 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‎‏‎‎‎‎‎‏‏‎‏‏‏‎‎‏‏‏‎‏‎‏‏‏‏‎‏‎‎‎‏‎‎‎‎‎‏‏‏‎‎‎‎‎‎‎‏‏‏‎‏‏‏‎‎Issue registering Wi‑Fi calling with your carrier: ‎‏‎‎‏‏‎<xliff:g id="CODE">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‏‎‎‏‎‏‎‏‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‎‎‎‏‎‏‏‎‎‏‎‏‏‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎%s‎‏‎‎‏‎"</item>
-    <item msgid="4397097370387921767">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‎‎‏‎‏‏‎‏‎‎‎‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‏‎‎‏‏‎‎‎‏‏‎‏‎‏‏‏‎‏‏‎‏‏‎‎‏‏‏‎%s Wi-Fi Calling‎‏‎‎‏‎"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‏‏‏‎‎‎‏‏‎‎‏‎‏‏‎‎‎‎‏‏‎‏‎‏‏‏‎‎‏‎‎‎‏‎‏‏‎‏‎‏‏‏‏‎‏‏‏‏‏‏‎‎‏‎‎‎‎‎‏‎‎‏‏‎<xliff:g id="SPN">%s</xliff:g>‎‏‎‎‏‏‏‎ Wi-Fi Calling‎‏‎‎‏‎"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‏‎‏‎‎‎‎‏‎‏‎‏‏‏‏‎‎‏‎‎‏‏‏‎‎‏‎‏‎‏‏‏‏‎‎‏‎‎‎‏‏‏‎‎‏‎‏‏‎‎‎‎‎‏‎WLAN Call‎‏‎‎‏‎"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‏‎‎‎‎‏‎‏‏‎‎‎‏‎‏‎‏‏‎‎‎‏‏‎‎‏‎‏‎‏‏‎‎‏‎‎‎‏‎‎‏‎‎‏‏‏‏‏‏‏‎‎‎‎‎‎‏‎‎‏‏‎<xliff:g id="SPN">%s</xliff:g>‎‏‎‎‏‏‏‎ WLAN Call‎‏‎‎‏‎"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‏‎‏‏‎‎‏‏‏‎‎‎‏‏‎‎‏‏‎‎‎‏‏‏‏‎‏‏‏‎‎‎‏‏‎‏‏‎‏‏‎‏‎‎‏‎‏‏‏‎‏‎‎‏‎‎‎‏‎‎‏‏‎<xliff:g id="SPN">%s</xliff:g>‎‏‎‎‏‏‏‎ Wi-Fi‎‏‎‎‏‎"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‏‎‎‏‏‏‎‏‎‏‎‏‏‎‏‎‏‏‎‏‎‎‏‏‏‏‎‏‎‏‎‏‎‏‏‏‎‏‏‎‎‏‎WiFi Calling | ‎‏‎‎‏‏‎<xliff:g id="SPN">%s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‏‎‏‏‏‎‏‎‎‎‎‏‏‎‏‏‏‏‏‎‏‏‏‏‏‎‎‎‏‎‏‎‎‎‏‎‏‏‎‏‎‏‎‏‎‏‎‏‎‏‎‎‎‏‎‎‏‎‎‏‏‎<xliff:g id="SPN">%s</xliff:g>‎‏‎‎‏‏‏‎ VoWifi‎‏‎‎‏‎"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‏‏‎‎‎‎‎‎‎‎‏‏‎‏‏‎‎‎‎‏‎‎‎‎‎‎‏‎‎‎‏‏‏‏‎‎‎‏‏‎‎‏‏‎‎‏‎‎‎‏‎‎Off‎‏‎‎‏‎"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‏‏‎‏‎‏‏‎‎‏‎‎‎‎‎‏‏‏‎‎‏‎‏‎‏‎‎‎‏‎‎‎‏‏‎‎‏‏‎‎‏‏‎‏‎‎‏‏‎‏‏‎‏‏‏‏‏‎Wi-Fi preferred‎‏‎‎‏‎"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‏‏‎‎‏‎‏‏‏‏‏‎‎‏‎‎‏‏‏‎‎‏‎‎‎‏‏‏‎‏‏‏‎‎‏‎‎‎‎‏‎‏‎‎‏‎‎‏‎‏‏‏‏‎‏‎‎‎Mobile preferred‎‏‎‎‏‎"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‏‎‏‎‎‏‏‏‏‏‎‎‏‏‏‏‎‎‎‏‎‎‏‏‏‎‎‏‏‎‏‎‎‏‏‎‎‎‎‎‎‏‎‎‏‎‏‎‏‎‎‏‎‎Not recognized‎‏‎‎‏‎"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎‏‎‏‏‏‎‏‎‎‎‏‎‏‏‎‎‏‎‎‎‎‎‏‎‏‎‎‎‏‎‏‏‎‎‎‏‏‎‏‎‎‎‎‎‏‎‏‏‏‏‎‎‎‎‎Fingerprint authenticated‎‏‎‎‏‎"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‏‏‏‎‎‎‏‎‏‎‎‏‏‏‎‎‏‎‎‎‎‏‏‏‎‏‏‎‏‎‏‎‎‎‎‎‏‎‏‏‏‎‏‎‏‎‎‎‏‎‏‎‏‎‏‏‏‎Face authenticated‎‏‎‎‏‎"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‎‏‎‏‏‏‏‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‎‎‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‏‎‎‏‎‏‎‎Face authenticated, please press confirm‎‏‎‎‏‎"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‏‎‎‏‎‎‎‏‏‏‎‎‏‎‎‏‏‎‎‎‏‎‏‏‎‏‎‏‏‏‏‏‎‎‏‏‏‎‎‎‏‏‏‏‎‏‎‏‎‏‎‎‎Fingerprint hardware not available.‎‏‎‎‏‎"</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‎‏‎‎‏‏‏‎‎‎‎‎‏‎‏‏‏‎‎‏‎‎‏‏‎‎‏‏‏‎‏‎‎‏‏‏‎‎‏‏‏‏‎‎‏‎‏‏‏‎‎‎‏‏‎‎Fingerprint can\'t be stored. Please remove an existing fingerprint.‎‏‎‎‏‎"</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‎‎‎‎‎‎‎‎‏‎‏‎‏‎‏‏‏‎‎‏‏‎‎‏‎‎‏‏‏‏‏‏‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‎‏‏‎Fingerprint time out reached. Try again.‎‏‎‎‏‎"</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‏‏‎‏‎‏‏‏‎‎‎‎‎‎‎‏‎‏‏‏‎‎‏‏‎‏‏‎‎‎‎‎‏‎‏‏‏‏‎‎‎‎‎‏‏‎‏‏‏‎‎‏‏‎‎Face time out reached. Try again.‎‏‎‎‏‎"</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‎‎‏‎‏‎‎‎‎‏‏‎‎‎‎‏‏‎‎‏‎‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‎‎‎‏‏‎‎‎‎‎‎‎‎‎‎‏‎‎Face can’t be stored.‎‏‎‎‏‎"</string>
     <string name="face_error_canceled" msgid="283945501061931023">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‏‏‏‎‎‎‎‏‏‎‎‎‏‏‎‏‏‏‎‏‏‎‏‏‏‎‎‎‏‏‎‎‏‎‏‏‏‎‏‏‏‏‎‎‎‎‎‎‎‎‎‏‏‏‏‎Face operation canceled.‎‏‎‎‏‎"</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‎‏‏‎‏‏‏‏‏‎‏‎‏‏‏‎‎‎‎‎‏‏‎‏‎‎‏‎‏‎‏‏‎‎‎‏‏‏‎‏‏‎Face authentication canceled by user.‎‏‎‎‏‎"</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‏‏‏‎‎‏‏‎‎‎‏‎‏‎‎‎‎‏‎‎‎‏‏‏‏‎‏‏‏‎‎‎‎‏‎‎‎‎‏‎‏‏‎‎‎‎Too many attempts. Try again later.‎‏‎‎‏‎"</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‎‎‏‏‎‎‏‏‎‏‎‎‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‎‎‎‎‎‎‏‎‏‎‎‏‎‏‎‎‏‏‎‏‏‏‎‏‎‎Too many attempts. Facial authentication disabled.‎‏‎‎‏‎"</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‏‎‏‎‎‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‎‎‏‎‏‎‎‎‏‏‎‏‎‎‎‏‏‎‎‏‏‏‎‎‏‏‎‎Try again.‎‏‎‎‏‎"</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‎‎‏‎‏‎‏‎‎‏‏‏‏‎‎‏‎‎‏‎‏‎‏‎‏‎‏‎‎‎‏‏‏‎‏‎‏‏‎‎‏‏‏‏‏‏‎‎‎‏‏‎‏‎‏‎Color Correction‎‏‎‎‏‎"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‏‏‎‏‏‎‎‏‎‏‎‏‏‎‎‎‎‏‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‏‏‏‎‏‏‎‎‎‎‎‏‏‎‎‏‏‎‎‎Accessibility Shortcut turned ‎‏‎‎‏‏‎<xliff:g id="SERVICE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ on‎‏‎‎‏‎"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‏‎‎‎‎‎‎‎‏‎‏‎‏‏‎‏‎‏‏‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‏‎‏‎‏‏‏‎‏‎‏‏‏‏‎‏‎Accessibility Shortcut turned ‎‏‎‎‏‏‎<xliff:g id="SERVICE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ off‎‏‎‎‏‎"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‎‎‎‎‏‏‎‏‏‎‏‎‏‏‏‎‏‎‏‏‏‎‎‏‎‎‎‏‏‏‎‏‏‎‏‏‏‎‏‏‎‏‎‎‎‎‏‏‏‎‏‏‎‏‎Use Accessibility Shortcut again to start the current accessibility feature‎‏‎‎‏‎"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‎‎‏‎‎‎‎‏‎‏‎‏‎‏‎‏‏‏‎‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‎‎‏‏‎‏‏‏‎‏‎‏‏‏‎‏‎‏‏‎Choose a feature to use when you tap the Accessibility button:‎‏‎‎‏‎"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‎‏‏‎‎‎‎‎‎‎‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‎‎‎‎‏‏‎‏‎‏‏‏‎‏‎‏‏‏‎‎‏‎‎‏‏‏‎‎‏‎To change features, touch &amp; hold the Accessibility button.‎‏‎‎‏‎"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‎‎‎‎‎‏‏‏‏‎‏‏‎‎‏‏‎‏‏‏‎‏‎‏‎‎‎‎‏‎‏‏‎‏‎‏‏‏‎‏‏‎‏‏‎‏‏‏‎‏‏‏‏‏‎‏‎Magnification‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index f317a4e..6176b7b 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Error al registrar la Llamada con Wi‑Fi con tu operador: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"Llamada por Wi-Fi de %s"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Llamada por Wi-Fi de <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Llamada por WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Llamada por WLAN de <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi de <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Llamada por Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi de <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Desactivada"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Red Wi-Fi preferida"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Red móvil preferida"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"No se reconoció"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Se autenticó la huella digital"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Se autenticó el rostro"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Se autenticó el rostro; presiona Confirmar"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"El hardware para detectar huellas digitales no está disponible."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"No se puede almacenar la huella digital. Elimina una de las existentes."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Finalizó el tiempo de espera para la huella digital. Vuelve a intentarlo."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Se agotó el tiempo. Vuelve a intentarlo."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"No se puede almacenar el rostro."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Se canceló el reconocimiento facial."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"El usuario canceló la autenticación de rostro."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Demasiados intentos. Inténtalo de nuevo más tarde."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Demasiados intentos. Autent. facial inhabilitada."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Vuelve a intentarlo."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Corrección de color"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"El acceso directo de accesibilidad activó <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"El acceso directo de accesibilidad desactivó <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Vuelve a usar el acceso directo de accesibilidad para iniciar la función de accesibilidad actual"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Elige una función para usar cuando presionas el botón Accesibilidad:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Para cambiar funciones, mantén presionado el botón Accesibilidad."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ampliación"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index c42f53c..dd766f7 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"No se ha podido registrar la llamada por Wi‑Fi con tu operador: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"Llamadas Wi-Fi de %s"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Llamada por Wi‑Fi de <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Llamada por WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Llamada por WLAN de <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi‑Fi de <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Llamada por Wi‑Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWiFi de <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Desactivado"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Dar preferencia a Wi-Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Preferir datos móviles"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"No se reconoce"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Se ha autenticado la huella digital"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Cara autenticada"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Se ha autenticado la cara, pulsa para confirmar"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"El hardware de huella digital no está disponible."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"No se puede almacenar la huella digital. Elimina una ya creada."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Se ha alcanzado el tiempo de espera de la huella digital. Vuelve a intentarlo."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Has sobrepasado el tiempo. Inténtalo de nuevo."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"No se pueden registrar más caras."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Se ha cancelado el reconocimiento facial."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"El usuario ha cancelado la autenticación de la cara."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Demasiados intentos. Inténtalo de nuevo más tarde."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Demasiados intentos. Autent. facial inhabilitada."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Inténtalo de nuevo."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Corrección de color"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"El acceso directo a accesibilidad ha activado <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"El acceso directo a accesibilidad ha desactivado <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Usa de nuevo la combinación de teclas de accesibilidad para iniciar la función de accesibilidad actual"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Selecciona la función que se utilizará cuando toques el botón Accesibilidad:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Para cambiar las funciones, mantén pulsado el botón Accesibilidad."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ampliar"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index cc052c4..650fcb6 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Probleem WiFi-kõnede registreerimisel teie operaatoriga: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s WiFi kaudu helistamine"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g>: WiFi-kõned"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN-kõne"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g>: WLAN-kõne"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g>: WiFi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"WiFi-kõne | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g>: VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Väljas"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"WiFi eelistusega"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Eelistatud on mobiilne andmeside"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Ei tuvastatud"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Sõrmejälg autenditi"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Nägu on autenditud"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Nägu on autenditud, vajutage käsku Kinnita"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Sõrmejälje riistvara pole saadaval."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Sõrmejälge ei saa salvestada. Eemaldage olemasolev sõrmejälg."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Sõrmejälje riistvara taimeri ajalõpp. Proovige uuesti."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Näotuvastuse taimeri ajalõpp. Proovige uuesti."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Nägu ei saa salvestada."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Näotuvastuse toiming tühistati."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Kasutaja tühistas näo autentimise."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Liiga palju katseid. Proovige hiljem uuesti."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Liiga palju katseid. Näotuvastus on keelatud."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Proovige uuesti."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Värviparandus"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Juurdepääsetavuse otsetee lülitas teenuse <xliff:g id="SERVICE_NAME">%1$s</xliff:g> sisse"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Juurdepääsetavuse otsetee lülitas teenuse <xliff:g id="SERVICE_NAME">%1$s</xliff:g> välja"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Praeguse juurdepääsufunktsiooni käivitamiseks kasutage juurdpääsetavuse otseteed uuesti"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Valige, millist funktsiooni kasutada, kui vajutate nuppu Juurdepääsetavus:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Funktsioonide muutmiseks puudutage pikalt nuppu Juurdepääsetavus."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Suurendus"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 275e171..6a6fdbf 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Arazo bat izan da Wi‑Fi bidezko deiak zure operadorearekin erregistratzean: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Wi-Fi bidezko deiak"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi bidezko deiak"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN bidezko deia"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN bidezko deia"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi bidezko deiak | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Desaktibatuta"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi sarea hobesten da"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Datu-konexioa hobesten da"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Ez da ezagutu"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Autentifikatu da hatz-marka"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Autentifikatu da aurpegia"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Autentifikatu da aurpegia; sakatu Berretsi"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hatz-markaren hardwarea ez dago erabilgarri."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Ezin da gorde hatz-marka digitala. Kendu lehendik gordeta duzunetako bat."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Hatz-marka digitalak prozesatzeko denbora-muga gainditu da. Saiatu berriro."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Gainditu da aurpegiak prozesatzeko denbora-muga. Saiatu berriro."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Ezin da gorde aurpegia."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Utzi da aurpegiaren bidezko eragiketa."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Erabiltzaileak utzi du aurpegi-autentifikazioa."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Saiakera gehiegi egin dituzu. Saiatu berriro geroago."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Saiakera gehiegi egin dituzu. Desgaitu egin da autentifikazioa."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Saiatu berriro."</string>
@@ -1129,7 +1136,7 @@
     <string name="aerr_application_repeated" msgid="3146328699537439573">"Behin eta berriz gelditzen ari da <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
     <string name="aerr_process_repeated" msgid="6235302956890402259">"Behin eta berriz gelditzen ari da <xliff:g id="PROCESS">%1$s</xliff:g>"</string>
     <string name="aerr_restart" msgid="7581308074153624475">"Ireki aplikazioa berriro"</string>
-    <string name="aerr_report" msgid="5371800241488400617">"Bidali iritzia"</string>
+    <string name="aerr_report" msgid="5371800241488400617">"Bidali oharrak"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Itxi"</string>
     <string name="aerr_mute" msgid="1974781923723235953">"Ezkutatu gailua berrabiarazi arte"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Itxaron"</string>
@@ -1617,6 +1624,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Koloreen zuzenketa"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Erabilerraztasun-lasterbideak <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aktibatu du"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Erabilerraztasun-lasterbideak <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desaktibatu du"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Uneko erabilerraztasun-eginbidea abiarazteko, erabili erabilerraztasun-lasterbidea berriro"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Aukeratu zein eginbide erabili nahi duzun Erabilerraztasuna botoia sakatzean:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Eginbideak aldatzeko, eduki sakatuta Erabilerraztasuna botoia."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Lupa"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 5055e8b..2310f9e 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"‏مشکل هنگام ثبت تماس ازطریق Wi‑Fi با شرکت مخابراتی: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"‏تماس ‪%s Wi-Fi"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"‏تماس ازطریق Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"‏تماس ازطریق WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"‏تماس ازطریق WLAN <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"‏درحال تماس ازطریق WiFi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"خاموش"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"‏Wi-Fi ترجیحی"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"داده شبکه تلفن همراه ارجح است"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"شناسایی نشد"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"اثر انگشت احراز هویت شد"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"چهره احراز هویت شد"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"چهره احراز هویت شد، لطفاً تأیید را فشار دهید"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"سخت‌افزار اثرانگشت در دسترس نیست."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"ذخیره اثر انگشت ممکن نیست. لطفاً یک اثر انگشت موجود را حذف کنید."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"مهلت زمانی ثبت اثر انگشت به پایان رسید. دوباره امتحان کنید."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"مهلت زمانی شناسایی چهره تمام شد. دوباره امتحان کنید"</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"نمی‌توان چهره را ذخیره کرد."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"عملیات شناسایی چهره لغو شد."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"احراز هویت چهره توسط کاربر لغو شد."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"تعداد زیادی تلاش ناموفق. بعداً دوباره امتحان کنید."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"چندین تلاش ناموفق. احراز هویت با چهره غیرفعال شد."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"دوباره امتحان کنید."</string>
@@ -890,7 +897,7 @@
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"ماندن در این صفحه"</string>
     <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nمطمئنید می‌خواهید این صفحه را ترک کنید؟"</string>
     <string name="save_password_label" msgid="6860261758665825069">"تأیید"</string>
-    <string name="double_tap_toast" msgid="4595046515400268881">"نکته: برای بزرگ‌نمایی و کوچک‌نمایی، دو بار ضربه بزنید."</string>
+    <string name="double_tap_toast" msgid="4595046515400268881">"نکته: برای نزدیک‌نمایی و دورنمایی، دو بار ضربه بزنید."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"تکمیل خودکار"</string>
     <string name="setup_autofill" msgid="7103495070180590814">"راه‌اندازی تکمیل خودکار"</string>
     <string name="autofill_window_title" msgid="4107745526909284887">"تکمیل خودکار با <xliff:g id="SERVICENAME">%1$s</xliff:g>"</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"تصحیح رنگ"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"«میان‌بر دسترس‌پذیری» <xliff:g id="SERVICE_NAME">%1$s</xliff:g> را روشن کرد"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"«میان‌بر دسترس‌پذیری» <xliff:g id="SERVICE_NAME">%1$s</xliff:g> را خاموش کرد"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"برای راه‌اندازی ویژگی دسترس‌پذیری کنونی، دوباره از «میان‌بر دسترس‌پذیری» استفاده کنید"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"قابلیتی را انتخاب کنید که هنگام ضربه زدن روی دکمه «دسترس‌پذیری» استفاده می‌شود:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"برای تغییر دادن قابلیت‌ها، دکمه «دسترس‌پذیری» را لمس کنید و نگه‌دارید."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"درشت‌نمایی"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index d54cb72..4f2531c 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Virhe otettaessa Wi-Fi-puheluita käyttöön operaattorille <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"Wi-Fi-puhelut: %s"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Wi-Fi-puhelut (<xliff:g id="SPN">%s</xliff:g>)"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN-puhelu"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"WLAN-puhelu (<xliff:g id="SPN">%s</xliff:g>)"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi-puhelut | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Ei käytössä"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi ensisijainen"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Mobiiliverkko ensisijainen"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Ei tunnistettu"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Sormenjälki tunnistettu"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Kasvot tunnistettu"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Kasvot tunnistettu, valitse Vahvista"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Sormenjälkilaitteisto ei ole käytettävissä."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Sormenjälkeä ei voida tallentaa. Poista aiemmin lisätty sormenjälki."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Sormenjälkitunnistimen toiminta aikakatkaistiin. Yritä uudelleen."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Kasvotoiminto aikakatkaistiin. Yritä uudelleen."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Kasvoja ei voi tallentaa."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Kasvotoiminto peruutettu"</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Käyttäjä peruutti kasvojentunnistuksen."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Liian monta yritystä. Yritä myöhemmin uudelleen."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Liikaa yrityksiä. Kasvojentodennus ei käytössä."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Yritä uudelleen."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Värinkorjaus"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> otettiin käyttöön esteettömyystilan pikanäppäimellä."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> poistettiin käytöstä esteettömyystilan pikanäppäimellä."</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Valitse esteettömyystilan oikopolku uudelleen käynnistääksesi esteettömyysominaisuuden"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Valitse toiminto, jonka Esteettömyys-painike aktivoi:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Jos haluat muokata ominaisuuksia, kosketa Esteettömyys-painiketta pitkään."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Suurennus"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 0c0cdea..39889ec 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Une erreur s\'est produite lors de l\'enregistrement des appels Wi-Fi avec votre fournisseur de services : <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"Appels Wi-Fi %s"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Appels Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Appel WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Appel WLAN <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Appels Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"Voix par Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Désactivé"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Réseau Wi-Fi de préférence"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Connexion cellulaire de préférence"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Données biométriques non reconnues"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Empreinte digitale authentifiée"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Visage authentifié"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Visage authentifié, veuillez appuyer sur le bouton Confirmer"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Matériel d\'empreinte numérique indisponible."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"L\'empreinte digitale ne peut pas être enregistrée. Veuillez supprimer une empreinte existante."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Le temps attribué pour lire l\'empreinte est écoulé. Veuillez essayer de nouveau."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Temps de reconn. visage écoulé. Veuillez réessayer."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Impossible de stocker le visage."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Opération de reconnaissance du visage annulée."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Authentification du visage annulée par l\'utilisateur"</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Trop de tentatives. Veuillez réessayer plus tard."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Trop de tentatives. Capt. reconn. visage désactivé."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Réessayez."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Correction des couleurs"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Le raccourci d\'accessibilité a activé la fonction <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Le raccourci d\'accessibilité a désactivé la fonction <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Utilisez à nouveau le raccourci d\'accessibilité pour démarrer la fonctionnalité d\'accessibilité actuelle"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Choisissez une fonctionnalité à utiliser lorsque vous touchez le bouton d\'accessibilité :"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Pour changer des fonctionnalités, maintenez le doigt sur le bouton d\'accessibilité."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Zoom"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index e153082..9759415 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Problème lors de l\'enregistrement des appels Wi‑Fi avec votre opérateur : <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"Appels Wi-Fi %s"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Appels Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Appel WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Appel WLAN <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Appels Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWiFi <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Désactivé"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi de préférence"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Priorité au mobile"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Non reconnu"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Empreinte digitale authentifiée"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Visage authentifié"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Visage authentifié, veuillez appuyer sur \"Confirmer\""</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Matériel d\'empreinte numérique indisponible."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Impossible d\'enregistrer l\'empreinte numérique. Veuillez supprimer une empreinte."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Délai de détection de l\'empreinte numérique expiré. Veuillez réessayer."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Délai de détection du visage expiré. Réessayez."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Impossible de stocker les informations du visage."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Opération de reconnaissance faciale annulée."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Authentification faciale annulée par l\'utilisateur."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Trop de tentatives. Réessayez plus tard."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Trop d\'essais. Authentification faciale désactivée."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Réessayez."</string>
@@ -1300,14 +1307,14 @@
     <string name="perm_costs_money" msgid="4902470324142151116">"Cela peut engendrer des frais"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_charging_notification_title" msgid="1595122345358177163">"Appareil en charge via USB"</string>
-    <string name="usb_supplying_notification_title" msgid="4631045789893086181">"Rechargement via USB de l\'appareil connecté"</string>
+    <string name="usb_supplying_notification_title" msgid="4631045789893086181">"Recharge via USB de l\'appareil connecté"</string>
     <string name="usb_mtp_notification_title" msgid="4238227258391151029">"Transfert de fichiers via USB activé"</string>
     <string name="usb_ptp_notification_title" msgid="5425857879922006878">"PTP via USB activé"</string>
     <string name="usb_tether_notification_title" msgid="3716143122035802501">"Partage de connexion via USB activé"</string>
     <string name="usb_midi_notification_title" msgid="5356040379749154805">"MIDI via USB activé"</string>
     <string name="usb_accessory_notification_title" msgid="1785694450621427730">"Accessoire USB connecté"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Appuyez ici pour plus d\'options."</string>
-    <string name="usb_power_notification_message" msgid="4647527153291917218">"Rechargement de l\'appareil connecté. Appuyez ici pour plus d\'options."</string>
+    <string name="usb_power_notification_message" msgid="4647527153291917218">"Recharge de l\'appareil connecté. Appuyez ici pour plus d\'options."</string>
     <string name="usb_unsupported_audio_accessory_title" msgid="3529881374464628084">"Accessoire audio analogique détecté"</string>
     <string name="usb_unsupported_audio_accessory_message" msgid="6309553946441565215">"L\'appareil connecté n\'est pas compatible avec ce téléphone. Appuyez ici pour en savoir plus."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Débogage USB activé"</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Correction des couleurs"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Le raccourci d\'accessibilité a activé <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Le raccourci d\'accessibilité a désactivé <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Utilisez à nouveau le raccourci d\'accessibilité pour démarrer la fonctionnalité d\'accessibilité actuelle"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Choisissez une fonctionnalité à utiliser lorsque vous appuyez sur le bouton d\'accessibilité :"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Pour changer des fonctionnalités, appuyez de manière prolongée sur le bouton d\'accessibilité."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Agrandissement"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index ba66adf..318dd3e 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Produciuse un problema ao rexistrar as chamadas por wifi co teu operador: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"Chamadas por wifi de %s"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Chamadas por wifi de <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Chamada por WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Chamada por WLAN de <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wifi de <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Chamadas por wifi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi de <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Desactivado"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wifi preferida"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Datos móbiles preferidos"</string>
@@ -298,8 +302,8 @@
     <string name="permgroupdesc_phone" msgid="6234224354060641055">"facer e xestionar chamadas telefónicas"</string>
     <string name="permgrouprequest_phone" msgid="9166979577750581037">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; realice e xestione chamadas telefónicas?"</string>
     <string name="permgrouplab_sensors" msgid="416037179223226722">"Sensores corporais"</string>
-    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"acceder aos datos do sensor sobre as túas constantes vitais"</string>
-    <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda aos datos do sensor sobre as túas constantes vitais?"</string>
+    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"acceder aos datos dos sensores sobre as túas constantes vitais"</string>
+    <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda aos datos dos sensores sobre as túas constantes vitais?"</string>
     <string name="permgrouplab_aural" msgid="965607064083134896">"Música"</string>
     <string name="permgroupdesc_aural" msgid="4870189506255958055">"acceder á música"</string>
     <string name="permgrouprequest_aural" msgid="6787926123071735620">"Queres permitir que a aplicación &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda á túa música?"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Non se recoñeceu"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Autenticouse a impresión dixital"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Autenticouse a cara"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Autenticouse a cara, preme Confirmar"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware de impresión dixital non dispoñible."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Non se pode almacenar a impresión dixital. Elimina unha impresión dixital existente."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Esgotouse o tempo de espera da impresión dixital. Téntao de novo."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Esgotouse o tempo de espera. Téntao de novo."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Non se puido almacenar a cara."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Cancelouse a operación relacionada coa cara"</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"O usuario cancelou a autenticación da cara."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Demasiados intentos. Téntao de novo máis tarde."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Demasiados intentos. Autenticación desactivada."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Téntao de novo."</string>
@@ -1617,6 +1624,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Corrección de cor"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"O atallo de accesibilidade activou <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"O atallo de accesibilidade desactivou <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Para iniciar a función de accesibilidade actual, utiliza de novo o atallo de accesibilidade"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Escolle que función queres utilizar cando toques o botón Accesibilidade:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Para cambiar as funcións, mantén premido o botón Accesibilidade."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ampliación"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 2b96f3f..13090c6 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"તમારા કૅરિઅરમાં વાઇ-ફાઇ કૉલિંગ રજિસ્ટર કરવામાં સમસ્યા આવી: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s વાઇ-ફાઇ કૉલિંગ"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> વાઇ-ફાઇ કૉલિંગ"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN કૉલ"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN કૉલ"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> વાઇ-ફાઇ"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"વાઇ-ફાઇ કૉલિંગ | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"બંધ"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"વાઇ-ફાઇ પસંદ કર્યું"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"મોબાઇલને પસંદગી"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"ઓળખાયેલ નથી"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"ફિંગરપ્રિન્ટ પ્રમાણિત કરી"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"ચહેરા પ્રમાણિત"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"ચહેરા પ્રમાણિત, કૃપા કરીને કન્ફર્મ કરો"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ફિંગરપ્રિન્ટ હાર્ડવેર ઉપલબ્ધ નથી."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"ફિંગરપ્રિન્ટ સંગ્રહિત કરી શકાતી નથી. કૃપા કરીને અસ્તિત્વમાંની ફિંગરપ્રિન્ટ દૂર કરો."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"ફિંગરપ્રિન્ટનો સમય બાહ્ય થયો. ફરી પ્રયાસ કરો."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"ચહેરા માટેનો સમય સમાપ્ત થયો. ફરી પ્રયાસ કરો."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"ચહેરો સંગ્રહિત કરી શકાશે નહીં."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"ચહેરા સંબંધિત કાર્યવાહી રદ કરવામાં આવી છે."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"વપરાશકર્તાએ ચહેરા પ્રમાણીકરણ રદ કર્યુ."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"ઘણા બધા પ્રયત્નો. થોડા સમય પછી ફરી પ્રયાસ કરો."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"ઘણા બધા પ્રયત્નો. ચહેરાનું પ્રમાણીકરણ બંધ કરવામાં આવ્યું છે."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"ફરી પ્રયાસ કરો."</string>
@@ -1617,6 +1624,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"રંગ સુધારણા"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ઍક્સેસિબિલિટી શૉર્ટકટે <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ચાલુ કરી"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ઍક્સેસિબિલિટી શૉર્ટકટે <xliff:g id="SERVICE_NAME">%1$s</xliff:g> બંધ કરી"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"વર્તમાન ઍક્સેસિબિલિટી સુવિધાને શરૂ કરવા માટે ફરીથી ઍક્સેસિબિલિટી શૉર્ટકટનો ઉપયોગ કરો"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"જ્યારે તમે ઍક્સેસિબિલિટી બટન પર ટૅપ કરો, ત્યારે ઉપયોગ કરવાની સુવિધા પસંદ કરો:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"સુવિધાઓ બદલવા માટે, ઍક્સેસિબિલિટી બટન દબાવી રાખો."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"વિસ્તૃતીકરણ"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 6afe603..6ae2541 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"वाई-फ़ाई कॉलिंग की सुविधा के लिए आपकी मोबाइल और इंटरनेट सेवा देने वाली कंपनी के साथ रजिस्टर करने से जुड़ी समस्या: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s वाई-फ़ाई कॉलिंग"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> वाई-फ़ाई कॉलिंग"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN कॉल"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN कॉल"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> वाई-फ़ाई"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"वाई-फ़ाई कॉलिंग | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"बंद"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"वाई-फ़ाई को प्राथमिकता"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"मोबाइल को प्राथमिकता"</string>
@@ -526,6 +530,8 @@
     <!-- no translation found for biometric_not_recognized (5770511773560736082) -->
     <skip />
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"फ़िंगरप्रिंट की पुष्टि हो गई"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"चेहरे की पहचान की गई"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"चेहरा की पहचान की गई, कृपया पुष्टि बटन दबाएं"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"फ़िंगरप्रिंट हार्डवेयर उपलब्ध नहीं है."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"फ़िंगरप्रिंट को संग्रहित नहीं किया जा सका. कृपया कोई मौजूदा फ़िंगरप्रिंट निकालें."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"फ़िंगरप्रिंट का समय समाप्त हो गया. पुनः प्रयास करें."</string>
@@ -562,6 +568,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"चेहरे की पहचान का समय खत्म हुआ. फिर से कोशिश करें."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"चेहरा सेव करने की सीमा पूरी हो गई है."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"चेहरा पहचानने की कार्रवाई रद्द की गई."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"उपयोगकर्ता ने चेहरे की पहचान रद्द कर दी."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"कई बार कोशिश की गई. बाद में कोशिश करें."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"कई बार कोशिश की. चेहरा पहचानने की सुविधा बंद हुई."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"फिर से कोशिश करें."</string>
@@ -1618,6 +1625,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"रंग में सुधार करने की सुविधा"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"सुलभता शॉर्टकट ने <xliff:g id="SERVICE_NAME">%1$s</xliff:g> को चालू किया"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"सुलभता शॉर्टकट ने <xliff:g id="SERVICE_NAME">%1$s</xliff:g> को बंद किया"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"मौजूदा सुलभता सुविधा शुरू करने के लिए \'सुलभता शॉर्टकट\' का फिर से इस्तेमाल करें"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"सुलभता बटन पर टैप करते समय इस्तेमाल की जाने वाली सुविधा चुनें:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"सुविधाओं में बदलाव करने के लिए, सुलभता बटन को दबाकर रखें."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"बड़ा करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index e7b6b5f..839d423 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -129,10 +129,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Poteškoća s registracijom Wi‑Fi poziva kod mobilnog operatera: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Wi-Fi pozivanje"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi pozivi"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Poziv putem WLAN-a"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> poziv putem WLAN-a"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi pozivi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Isključeno"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Prednost ima Wi-Fi mreža"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Za mobilne uređaje"</string>
@@ -527,6 +531,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Nije prepoznato"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Autentificirano otiskom prsta"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Lice je autentificirano"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Lice je autentificirano, pritisnite Potvrdi"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardver za otisak prsta nije dostupan."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Otisak prsta nije pohranjen. Uklonite postojeći otisak prsta."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Isteklo je vrijeme čekanja za otisak prsta. Pokušajte ponovo."</string>
@@ -563,6 +569,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Isteklo je vrijeme čekanja za lice. Pokušajte opet"</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Nije moguće pohraniti lice."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Otkazana je radnja s licem."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Autentifikaciju lica otkazao je korisnik."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Previše pokušaja. Pokušajte ponovo kasnije."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Previše pokušaja. Autentifikacija lica onemogućena"</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Pokušajte ponovo."</string>
@@ -1640,6 +1647,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Korekcija boje"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Prečac pristupačnosti uključio je uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Prečac pristupačnosti isključio je uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Ponovo upotrijebite prečac pristupačnosti da biste pokrenuli trenutačnu značajku pristupačnosti"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Odaberite značajku koju ćete upotrebljavati kada dodirnete gumb Pristupačnost:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Da biste promijenili značajke, dodirnite i zadržite gumb Pristupačnost."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Povećavanje"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 3d9a35b..bc54bfa 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Hiba történt a Wi‑Fi-hívás szolgáltatónál való regisztrálása során: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Wi-Fi-hívás"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi-hívás"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN-hívás"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN-hívás"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi-hívás | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Ki"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi előnyben részesítve"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Preferált: mobil"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Nem ismerhető fel"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Ujjlenyomat hitelesítve"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Arc hitelesítve"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Arc hitelesítve; nyomja meg a Megerősítés lehetőséget"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Az ujjlenyomathoz szükséges hardver nem érhető el."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Az ujjlenyomat nem tárolható. Távolítson el egy meglévő ujjlenyomatot."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Az ujjlenyomat-beolvasási műveletkor időtúllépés történt. Próbálkozzon újra."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Időtúllépés az arcbeolvasásnál. Próbálja újra."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Az arc nem tárolható."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Az arccal kapcsolatos művelet törölve."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Az arc hitelesítését a felhasználó visszavonta."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Túl sok próbálkozás. Próbálja újra később."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Túl sok próbálkozás. Arcfelismerés letiltva."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Próbálkozzon újra."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Színkorrekció"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"A Kisegítő lehetőségek gyorsparancsa bekapcsolta a következő szolgáltatást: <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"A Kisegítő lehetőségek gyorsparancsa kikapcsolta a következő szolgáltatást: <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Használja újból a Kisegítő lehetőségek gyorsparancsát az aktuális kisegítő lehetőségek elindításához"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Válassza ki a Kisegítő lehetőségek gombra koppintáskor használni kívánt funkciót:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"A funkciók módosításához tartsa lenyomva a Kisegítő lehetőségek gombot."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Nagyítás"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 6a5f287..4a828fa 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Wi‑Fi-ի միջոցով արվող զանգերը չհաջողվեց գրանցել ձեր օպերատորի մոտ՝ <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Wi-Fi զանգեր"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi-ի միջոցով զանգեր"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Զանգ WLAN ցանցով"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN ցանցով զանգեր"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Զանգեր Wi-Fi-ի միջոցով | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Անջատված է"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi, նախընտրելի"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Նախընտրելի է բջջային ցանցը"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Չհաջողվեց ճանաչել"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Մատնահետքը նույնականացվեց"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Դեմքը ճանաչվեց"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Դեմքը ճանաչվեց: Սեղմեք «Հաստատել»:"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Մատնահետքի սարքն անհասանելի է:"</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Հնարավոր չէ պահել մատնահետքը: Հեռացրեք առկա մատնահետքը:"</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Մատնահետքի գրանցման ժամանակը սպառվել է: Փորձեք նորից:"</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Ժամանակը սպառվել է: Նորից փորձեք:"</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Դեմքը հնարավոր չէ պահել։"</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Դեմքի ճանաչումը չեղարկվել է։"</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Դեմքի ճանաչումը չեղարկվել է օգտատիրոջ կողմից:"</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Չափից շատ փորձեր եք կատարել: Փորձեք ավելի ուշ:"</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Չափից շատ փորձեր եք կատարել: Դեմքի ճանաչման գործառույթն անջատվել է։"</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Նորից փորձեք:"</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Գունաշտկում"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Մատչելիության դյուրանցումն միացրել է <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ծառայությունը"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Մատչելիության դյուրանցումն անջատել է <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ծառայությունը"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Հատուկ գործառույթների դյուրանցումը գործարկելու համար նորից օգտագործեք համապատասխան դյուրանցումը"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Ընտրեք որևէ գործառույթ, որը կօգտագործվի Հատուկ գործառույթներ կոճակին հպելու դեպքում՝"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Գործառույթները փոխելու համար հպեք և պահեք Հատուկ գործառույթներ կոճակը։"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Խոշորացում"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 6d1da48..167082d 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Terjadi masalah saat mendaftarkan panggilan Wi‑Fi dengan operator Anda: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Panggilan Wi-Fi"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Panggilan Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Panggilan WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Panggilan WLAN <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Panggilan WiFi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Nonaktif"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi dipilih"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Seluler dipilih"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Tidak dikenali"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Sidik jari diautentikasi"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Wajah diautentikasi"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Wajah diautentikasi, silakan tekan konfirmasi"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware sidik jari tidak tersedia."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Sidik jari tidak dapat disimpan. Hapus sidik jari yang ada."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Waktu sidik jari habis. Coba lagi."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Waktu tunggu wajah habis. Harap coba lagi."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Wajah tidak dapat disimpan."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Pemrosesan wajah dibatalkan."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Autentikasi wajah dibatalkan oleh pengguna."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Terlalu banyak percobaan. Coba lagi nanti."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Terlalu sering dicoba. Autentikasi wajah dinonaktifkan."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Coba lagi."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Koreksi Warna"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Pintasan Aksesibilitas mengaktifkan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Pintasan Aksesibilitas menonaktifkan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Gunakan Pintasan Aksesibilitas lagi untuk memulai fitur aksesibilitas saat ini"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Pilih fitur yang akan digunakan saat menge-tap tombol Aksesibilitas:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Untuk mengubah fitur, sentuh &amp; tahan tombol Aksesibilitas."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Pembesaran"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 4d7996f..0c7e6b8 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Vandamál kom upp við að skrá Wi‑Fi símtöl hjá símafyrirtækinu: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Wi-Fi símtöl"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi símtöl"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN-símtal"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN-símtal"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi símtal | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Slökkt"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi í forgangi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Farsímakerfi í forgangi"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Þekktist ekki"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingrafar staðfest"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Andlit staðfest"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Andlit staðfest, ýttu til að staðfesta"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Fingrafarsvélbúnaður ekki til staðar."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Ekki er hægt að vista fingrafarið. Fjarlægðu eitthvert af fingraförunum sem fyrir eru."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Tímamörk runnu út fyrir fingrafar. Reyndu aftur."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Tímamörk runnu út fyrir andlit. Reyndu aftur."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Ekki tókst að geyma andlit."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Hætt við andlitsgreiningu."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Notandi hætti við andlitsgreiningu."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Of margar tilraunir. Reyndu aftur síðar."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Of margar tilraunir. Slökkt á andlitsgreiningu."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Reyndu aftur."</string>
@@ -1617,6 +1624,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Litaleiðrétting"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Flýtileið aðgengisstillingar kveikti á <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Flýtileið aðgengisstillingar slökkti á <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Notaðu flýtileið aðgengisstillingar aftur til að opna aðgengiseiginleika"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Veldu eiginleika sem á að nota þegar ýtt er á aðgengishnappinn:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Haltu fingri á aðgengishnappinum til að breyta eiginleikum."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Stækkun"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 44818a3..a6d5d23 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Si è verificato un problema con la registrazione delle chiamate Wi‑Fi con l\'operatore: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"Chiamata Wi-Fi %s"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Chiamate Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Chiamata WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Chiamata WLAN <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Chiamate Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Non attiva"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Rete preferita: Wi-Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Rete preferita: dati mobili"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Non riconosciuto"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Impronta digitale autenticata"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Volto autenticato"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Volto autenticato, premi Conferma"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware per l\'impronta digitale non disponibile."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Impossibile memorizzare l\'impronta digitale. Rimuovi un\'impronta esistente."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Timeout impronta digitale. Riprova."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Timeout operazione associata al volto. Riprova."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Il volto non può essere memorizzato."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Operazione associata al volto annullata."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Autenticazione del volto annullata dall\'utente."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Troppi tentativi. Riprova più tardi."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Troppi tentativi. Autenticazione disattivata."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Riprova."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Correzione del colore"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"La scorciatoia Accessibilità ha attivato <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"La scorciatoia Accessibilità ha disattivato <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Usa di nuovo la scorciatoia Accessibilità per avviare l\'attuale funzione di accessibilità"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Scegli una funzione da usare quando tocchi il pulsante Accessibilità:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Per cambiare le funzioni, tocca e tieni premuto il pulsante Accessibilità."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ingrandimento"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index fd5c2a1..48933f9 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -130,10 +130,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"‏אירעה בעיה ברישום שיחות Wi-Fi אצל הספק שלך: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"‏שיחות Wi-Fi של %s"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"‏שיחות Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"שיחה ברשת אלחוטית"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"‏שיחת WLAN <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"‏שיחות WiFi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"כבוי"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"‏Wi-Fi מועדף"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"מצב מועדף: רשת סלולרית"</string>
@@ -530,6 +534,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"לא זוהתה"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"טביעת האצבע אומתה"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"זיהוי הפנים בוצע"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"זיהוי הפנים בוצע. יש ללחוץ על אישור"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"החומרה בשביל טביעת אצבע אינה זמינה."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"לא ניתן לאחסן טביעת אצבע. הסר טביעת אצבע קיימת."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"חלף הזמן הקצוב לטביעת אצבע. נסה שוב."</string>
@@ -566,6 +572,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"חלף הזמן הקצוב לזיהוי הפנים. יש לנסות שוב."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"לא ניתן לשמור את הפנים."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"פעולת הפנים בוטלה."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"זיהוי הפנים בוטל על ידי המשתמש."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"יותר מדי ניסיונות. יש לנסות שוב מאוחר יותר."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"יותר מדי ניסיונות. אימות הפנים הושבת."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"יש לנסות שוב."</string>
@@ -1228,13 +1235,13 @@
     <string name="volume_call" msgid="3941680041282788711">"עוצמת קול בשיחה"</string>
     <string name="volume_bluetooth_call" msgid="2002891926351151534">"‏עוצמת הקול בשיחה ב-Bluetooth"</string>
     <string name="volume_alarm" msgid="1985191616042689100">"עוצמת קול של התראה"</string>
-    <string name="volume_notification" msgid="2422265656744276715">"עוצמת קול של הודעות"</string>
+    <string name="volume_notification" msgid="2422265656744276715">"עוצמת הקול של ההתראות"</string>
     <string name="volume_unknown" msgid="1400219669770445902">"עוצמת קול"</string>
     <string name="volume_icon_description_bluetooth" msgid="6538894177255964340">"‏עוצמת קול של Bluetooth"</string>
     <string name="volume_icon_description_ringer" msgid="3326003847006162496">"עוצמת קול של רינגטון"</string>
     <string name="volume_icon_description_incall" msgid="8890073218154543397">"עוצמת קול של שיחות"</string>
     <string name="volume_icon_description_media" msgid="4217311719665194215">"עוצמת קול של מדיה"</string>
-    <string name="volume_icon_description_notification" msgid="7044986546477282274">"עוצמת קול של הודעות"</string>
+    <string name="volume_icon_description_notification" msgid="7044986546477282274">"עוצמת הקול של ההתראות"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"רינגטון ברירת מחדל"</string>
     <string name="ringtone_default_with_actual" msgid="1767304850491060581">"ברירת מחדל (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"ללא"</string>
@@ -1502,7 +1509,7 @@
     <string name="sync_really_delete" msgid="2572600103122596243">"מחק את הפריטים"</string>
     <string name="sync_undo_deletes" msgid="2941317360600338602">"בטל את פעולות המחיקה"</string>
     <string name="sync_do_nothing" msgid="3743764740430821845">"אל תעשה דבר כרגע"</string>
-    <string name="choose_account_label" msgid="5655203089746423927">"בחר חשבון"</string>
+    <string name="choose_account_label" msgid="5655203089746423927">"בחירת חשבון"</string>
     <string name="add_account_label" msgid="2935267344849993553">"הוספת חשבון"</string>
     <string name="add_account_button_label" msgid="3611982894853435874">"הוספת חשבון"</string>
     <string name="number_picker_increment_button" msgid="2412072272832284313">"הוסף"</string>
@@ -1664,6 +1671,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"תיקון צבעים"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> הופעל על-ידי קיצור הדרך לנגישות"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> הושבת על-ידי קיצור הדרך לנגישות"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"יש להשתמש שוב במקש הקיצור לנגישות כדי להפעיל את תכונת הנגישות הנוכחית"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"בחר תכונה שתופעל כשתלחץ על הלחצן \'נגישות\':"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"כדי להחליף תכונה, גע בלחצן \'נגישות\' והחזק אותו."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"הגדלה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 4915111..994039c 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"携帯通信会社への Wi‑Fi 通話の登録中に問題が発生しました(<xliff:g id="CODE">%1$s</xliff:g>)"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"Wi-Fi通話(%s)"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi 通話"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN 通話"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN 通話"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi 通話 | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"OFF"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi優先"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"モバイル優先"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"認識されませんでした"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"指紋認証を完了しました"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"顔を認証しました"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"顔を認証しました。[確認] を押してください"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"指紋ハードウェアは使用できません。"</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"指紋を保存できません。既存の指紋を削除してください。"</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"指紋の読み取りがタイムアウトになりました。もう一度お試しください。"</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"読み取りのタイムアウトです。もう一度お試しください。"</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"顔の情報を保存できません。"</string>
     <string name="face_error_canceled" msgid="283945501061931023">"顔の操作をキャンセルしました。"</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"顔の認証がユーザーによりキャンセルされました。"</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"試行回数の上限です。後でもう一度お試しください。"</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"試行回数の上限です。顔認証は無効になりました。"</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"もう一度お試しください。"</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"色補正"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ユーザー補助機能のショートカットにより <xliff:g id="SERVICE_NAME">%1$s</xliff:g> は ON になっています"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ユーザー補助機能のショートカットにより <xliff:g id="SERVICE_NAME">%1$s</xliff:g> は OFF になっています"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"現在のユーザー補助機能を開始するには、ユーザー補助機能のショートカットをもう一度使用してください"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"[ユーザー補助] ボタンをタップした場合に使用する機能を選択してください。"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"機能を変更するには、[ユーザー補助] ボタンを押し続けてください。"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"拡大"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 51a4c28..a9ce748 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Wi‑Fi დარეკვის თქვენს ოპერატორთან რეგისტრირებისას შეცდომა წარმოიქმნა: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s დარეკვა Wi-Fi-ს მეშვეობით"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi დარეკვა"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN ზარი"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN ზარი"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi დარეკვა | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"გამორთული"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"სასურველია Wi-Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"უპირატესობა მიენიჭოს მობილურს"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"არ არის ამოცნობილი"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"თითის ანაბეჭდი ავტორიზებულია"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"სახე ავტორიზებულია"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"სახე ავტორიზებულია, დააჭირეთ დადასტურებას"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"თითის ანაბეჭდის აპარატურა არ არის ხელმისაწვდომი."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"თითის ანაბეჭდის შენახვა ვერ ხერხდება. გთხოვთ, ამოშალოთ არსებული თითის ანაბეჭდი."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"თითის ანაბეჭდის ლოდინის დრო ამოიწურა. სცადეთ ხელახლა."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"სახის ამოცნობის დრო ამოიწურა. ცადეთ ხელახლა."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"სახის შენახვა ვერ მოხერხდა."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"სახის ამოცნობა გაუქმდა."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"სახის ავტორიზაცია გაუქმდა მომხმარებლის მიერ."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"დაფიქსირდა ბევრი მცდელობა. ცადეთ მოგვიანებით."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"დაფიქსირდა ბევრი მცდელობა. სახის ამოცნობა გაითიშა."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"ცადეთ ხელახლა."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"ფერთა კორექცია"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"მარტივი წვდომის მალსახმობმა ჩართო <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"მარტივი წვდომის მალსახმობმა გამორთო <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"მარტივი წვდომის ამჟამინდელი ფუნქციის გასაშვებად გამოიყენეთ მარტივი წვდომის მალსახმობი"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"აირჩიეთ მარტივი წვდომის ღილაკზე შეხებისას გამოსაყენებელი ფუნქცია:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ფუნქციების შესაცვლელად ხანგრძლივად შეეხეთ მარტივი წვდომის ღილაკს."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"გადიდება"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 18be1e6..a8b527b 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Оператордың Wi‑Fi қоңырауын тіркеу кезінде қате шықты: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Wi-Fi арқылы қоңырау шалу"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi қоңыраулары"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN қоңырауы"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN қоңырауы"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi қоңыраулары | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Өшірулі"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Қалаулы Wi-Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Таңдаулы мобильдік байланыс"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Танылмады"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Саусақ ізі аутентификацияланды"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Бет танылды"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Бет танылды, \"Растау\" түймесін басыңыз"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Саусақ ізі жабдығы қолжетімді емес."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Саусақ ізін сақтау мүмкін емес. Бар саусақ ізін жойыңыз."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Саусақ ізін күту уақыты бітті. Әрекетті қайталаңыз."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Күту уақыты бітті. Әрекетті қайталаңыз."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Бетті сақтау мүмкін емес."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Бетті танудан бас тартылды."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Пайдаланушы бетті тану әрекетінен бас тартты."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Тым көп әрекет жасалды. Кейінірек қайталаңыз."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Тым көп әрекет жасалды. Бетті тану функциясы өшірілді."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Қайталап көріңіз."</string>
@@ -1617,6 +1624,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Түсті түзету"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Арнайы мүмкіндіктер таңбашасы <xliff:g id="SERVICE_NAME">%1$s</xliff:g> қызметін қосты"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Арнайы мүмкіндіктер таңбашасы <xliff:g id="SERVICE_NAME">%1$s</xliff:g> қызметін өшірді"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Арнайы мүмкіндіктер функциясын іске қосу үшін оның таңбашасын пайдаланыңыз"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"\"Арнайы мүмкіндіктер\" түймесін түрткенде пайдаланатын мүмкіндікті таңдаңыз:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Мүмкіндіктерді өзгерту үшін \"Арнайы мүмкіндіктер\" түймесін түртіп, ұстап тұрыңыз."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ұлғайту"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 091fa71..2620ce4 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"មាន​បញ្ហា​ក្នុង​ការ​ចុះ​ឈ្មោះ​ការហៅ​តាម Wi‑Fi ជាមួយ​ក្រុមហ៊ុន​សេវា​ទូរសព្ទ​របស់អ្នក៖ <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"ការហៅតាមរយៈ Wi-Fi %s"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> ការហៅតាម Wi-Fi"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"ការហៅ​តាម WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> ការហៅតាម WLAN"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"ការហៅតាម WiFi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"បិទ"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi ជាអាទិភាព"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"ទិន្នន័យទូរសព្ទចល័តជាអាទិភាព"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"មិនអាចសម្គាល់បានទេ"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"បាន​ផ្ទៀង​ផ្ទាត់​ស្នាម​ម្រាមដៃ"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"បានផ្ទៀងផ្ទាត់​មុខ"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"បានផ្ទៀងផ្ទាត់​មុខ សូម​ចុច​បញ្ជាក់"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ផ្នែករឹងស្នាមម្រាមដៃមិនមានទេ។"</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"មិនអាចផ្ទុកស្នាមម្រាមដៃទេ។ សូមយកស្នាមម្រាមដៃដែលមានស្រាប់ចេញ។"</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"ការផ្តិតម្រាមដៃបានអស់ពេល។ សូមព្យាយាមម្តងទៀត។"</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"ការសម្គាល់​ផ្ទៃមុខ​បាន​អស់ម៉ោង។ សូមព្យាយាមម្ដងទៀត។"</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"មិន​អាច​រក្សាទុក​ផ្ទៃ​មុខ​បានទេ។"</string>
     <string name="face_error_canceled" msgid="283945501061931023">"បាន​បោះបង់​ប្រតិបត្តិការចាប់​ផ្ទៃមុខ។"</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"ការផ្ទៀងផ្ទាត់​មុខ​ត្រូវបានបោះបង់ដោយអ្នកប្រើប្រាស់។"</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"ព្យាយាមចូលច្រើនពេកហើយ។ សូមព្យាយាមម្តងទៀតពេលក្រោយ។"</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"ព្យាយាមចូលច្រើនពេកហើយ។ បាន​បិទការផ្ទៀងផ្ទាត់​ផ្ទៃ​មុខ។"</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"សូមព្យាយាម​ម្ដងទៀត។"</string>
@@ -1618,6 +1625,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"ការ​កែ​ពណ៌"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ផ្លូវកាត់​ភាព​ងាយ​ស្រួល​បាន​បើក <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ផ្លូវកាត់​ភាព​ងាយ​ស្រួល​បាន​បិទ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"ប្រើផ្លូវកាត់​ភាពងាយស្រួល​ម្ដងទៀត ដើម្បី​ចាប់ផ្ដើម​មុខងារ​ភាពងាយប្រើ​បច្ចុប្បន្ន"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ជ្រើសរើស​មុខងារ​ដែលត្រូវ​ប្រើ នៅពេល​ដែល​អ្នកចុច​ប៊ូតុង​ភាពងាយស្រួល៖"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ដើម្បី​ផ្លាស់ប្តូរ​មុខងារ សូម​ចុច​ប៊ូតុង​ភាព​ងាយស្រួល​ឲ្យ​ជាប់។"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"ការ​ពង្រីក"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index e228d35..1b83ec2 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"ನಿಮ್ಮ ವಾಹಕದೊಂದಿಗೆ ವೈ-ಫೈ ಕರೆ ಮಾಡುವಿಕೆ ಸಮಸ್ಯೆ ನೋಂದಾಯಿಸುವಿಕೆ: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s ವೈ-ಫೈ ಕರೆ ಮಾಡುವಿಕೆ"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> ವೈ-ಫೈ ಕರೆ ಮಾಡುವಿಕೆ"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN ಕರೆ"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN ಕರೆ"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> ವೈ-ಫೈ"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"ವೈಫೈ ಕರೆಮಾಡುವಿಕೆ | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"ಆಫ್"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"ವೈ-ಫೈಗೆ ಆದ್ಯತೆ"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"ಮೊಬೈಲ್‌ಗೆ ಆದ್ಯತೆ"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"ಗುರುತಿಸಲಾಗಿಲ್ಲ"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಅನ್ನು ಪ್ರಮಾಣೀಕರಣ ಮಾಡಲಾಗಿದೆ"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"ಮುಖವನ್ನು ದೃಢೀಕರಿಸಲಾಗಿದೆ"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"ಮುಖವನ್ನು ದೃಢೀಕರಿಸಲಾಗಿದೆ, ದೃಢೀಕರಣವನ್ನು ಒತ್ತಿ"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ಬೆರಳಚ್ಚು ಹಾರ್ಡ್‌ವೇರ್‌ ಲಭ್ಯವಿಲ್ಲ."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"ಬೆರಳಚ್ಚು ಸಂಗ್ರಹಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ ಬೆರಳಚ್ಚು ತೆಗೆದುಹಾಕಿ."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"ಬೆರಳಚ್ಚು ಅವಧಿ ಮೀರಿದೆ. ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"ಮುಖ ಸಮಯದ ಅವಧಿಯನ್ನು ತಲುಪಿದೆ. ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"ಮುಖವನ್ನು ಸಂಗ್ರಹಿಸಲಾಗುವುದಿಲ್ಲ."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"ಮುಖದ ಕಾರ್ಯಚರಣೆಯನ್ನು ರದ್ದುಗೊಳಿಸಲಾಗಿದೆ."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"ಮುಖ ದೃಢೀಕರಣವನ್ನು ಬಳಕೆದಾರರ ಮೂಲಕ ರದ್ದುಗೊಳಿಸಲಾಗಿದೆ."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"ಹಲವು ಬಾರಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ನಂತರ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"ಹಲವು ಪ್ರಯತ್ನ. ಮುಖದ ದೃಢೀಕರಣ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
@@ -1617,6 +1624,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"ಬಣ್ಣ ತಿದ್ದುಪಡಿ"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ಪ್ರವೇಶಿಸುವಿಕೆ ಶಾರ್ಟ್‌ಕಟ್‌, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ಅನ್ನು ಆನ್ ಮಾಡಿದೆ"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ಪ್ರವೇಶಿಸುವಿಕೆ ಶಾರ್ಟ್‌ಕಟ್‌, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ಅನ್ನು ಆಫ್ ಮಾಡಿದೆ"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"ಪ್ರಸ್ತುತ ಪ್ರವೇಶದ ವೈಶಿಷ್ಟ್ಯವನ್ನು ಪ್ರಾರಂಭಿಸಲು ಪ್ರವೇಶಿಸುವಿಕೆ ಶಾರ್ಟ್‌ಕಟ್‌ ಅನ್ನು ಪುನಃ ಬಳಸಿ"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ನೀವು ಪ್ರವೇಶಿಸುವಿಕೆ ಬಟನ್ ಟ್ಯಾಪ್ ಮಾಡಿದಾಗ ಬಳಸುವುದಕ್ಕಾಗಿ ವೈಶಿಷ್ಟ್ಯವನ್ನು ಆರಿಸಿ:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಬದಲಾಯಿಸಲು, ಪ್ರವೇಶಿಸುವಿಕೆ ಬಟನ್ ಒತ್ತಿಹಿಡಿದುಕೊಳ್ಳಿ."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"ಹಿಗ್ಗಿಸುವಿಕೆ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index d37a475..6223dab 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"이동통신사를 통해 Wi‑Fi 통화를 등록하는 중에 문제가 발생했습니다. 오류 코드: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Wi-Fi 통화"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi 통화"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN 통화"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN 통화"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi 통화 | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"꺼짐"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi를 기본으로 설정"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"모바일에 최적화됨"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"인식할 수 없음"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"지문이 인증됨"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"얼굴이 인증되었습니다"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"얼굴이 인증되었습니다. 확인을 누르세요"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"지문 인식 하드웨어를 사용할 수 없습니다."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"지문을 저장할 수 없습니다. 기존 지문을 삭제하세요."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"지문 인식 시간이 초과되었습니다. 다시 시도하세요."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"얼굴 인식 시간이 초과되었습니다. 다시 시도하세요."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"얼굴을 저장할 수 없습니다."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"얼굴 인식 작업이 취소되었습니다."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"사용자가 얼굴 인증을 취소했습니다."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"시도 횟수가 너무 많습니다. 나중에 다시 시도하세요."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"시도 횟수가 너무 많아 얼굴 인증이 사용 중지되었습니다."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"다시 시도해 보세요."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"색상 보정"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"접근성 단축키로 인해 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>이(가) 사용 설정되었습니다."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"접근성 단축키로 인해 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>이(가) 사용 중지되었습니다."</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"현재 접근성 기능을 시작하려면 접근성 단축키를 다시 사용하세요"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"접근성 버튼을 탭할 때 사용할 기능을 선택하세요."</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"기능을 변경하려면 접근성 버튼을 길게 터치하세요."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"확대"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index cf5f531..f49746f 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Байланыш операторуңуз менен Wi-Fi аркылуу чалууну каттоодо ката кетти: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Wi-Fi Чалуу"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi аркылуу чалуу"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN аркылуу чалуу"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN аркылуу чалуу"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"WiFi аркылуу чалуу | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Өчүк"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi тандалган"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Тандалган мобилдик түзмөк"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Таанылган жок"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Манжа изинин аныктыгы текшерилди"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Жүздүн аныктыгы текшерилди"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Жүздүн аныктыгы текшерилди, эми \"Ырастоону\" басыңыз"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Манжа изинин аппараттык камсыздоосу жеткиликтүү эмес."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Манжа изин сактоо мүмкүн эмес. Учурдагы манжа изин алып салыңыз."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Манжа изин күтүү мөөнөтү бүттү. Кайра аракет кылыңыз."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Жүздүн аныктыгын текшерүүнү күтүү мөөнөтү бүттү. Кайра аракет кылыңыз."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Жүздү сактоо мүмкүн эмес."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Жүздүн аныктыгын текшерүү жокко чыгарылды."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Жүздүн аныктыгын текшерүү колдонуучу аркылуу жокко чыгарылды."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Өтө көп жолу аракет жасадыңыз. Кийинчерээк кайра аракет кылыңыз."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Өтө көп жолу аракет жасадыңыз. Жүздүн аныктыгын текшерүү сенсору өчүрүлдү."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Кайра аракет кылыңыз."</string>
@@ -1618,6 +1625,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Түсүн тууралоо"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Атайын мүмкүнчүлүктөр кыска жолу <xliff:g id="SERVICE_NAME">%1$s</xliff:g> кызматын күйгүздү"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Атайын мүмкүнчүлүктөр кыска жолу <xliff:g id="SERVICE_NAME">%1$s</xliff:g> кызматын өчүрдү"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Учурдагы атайын мүмкүнчүлүктөр функциясын иштетүү үчүн кыска жолду кайра колдонуңуз"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Атайын мүмкүнчүлүктөр баскычын таптаганыңызда иштетиле турган функцияны тандаңыз:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Функцияларды өзгөртүү үчүн Атайын мүмкүнчүлүктөр баскычын басып, кармап туруңуз."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Чоңойтуу"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 7d8a4e2..9fc6033 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"ເກີດບັນຫາໃນການລົງທະບຽນການໂທ Wi‑Fi ກັບຜູ້ໃຫ້ບໍລິການຂອງທ່ານ: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"ການ​ໂທ %s Wi-Fi"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi Calling"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN Call"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN Call"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"WiFi Calling | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"ປິດ"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"ເລືອກໃຊ້ Wi​-Fi ກ່ອນ"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"ຕ້ອງການໃຊ້ມືຖື"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"ບໍ່ຮັບຮູ້"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"ພິສູດຢືນຢັນລາຍນິ້ວມືແລ້ວ"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"ພິສູດຢືນຢັນໃບໜ້າແລ້ວ"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"ພິສູດຢືນຢັນໃບໜ້າແລ້ວ, ກະລຸນາກົດຢືນຢັນ"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ບໍ່​ມີ​ຮາດ​ແວລາຍ​ນີ້ວ​ມື​ໃຫ້​ຢູ່."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"ບໍ່​ສາ​ມາດ​ເກັບ​ຮັກ​ສາ​ລາຍ​ນີ້ວ​ມື​ໄວ້​ໄດ້. ກະ​ລຸ​ນາ​ເອົາ​ລາຍ​ນີ້ວ​ມື​ທີ່​ມີ​ຢູ່​ອອກ​ໄປ."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"ເວ​ລາ​ລາຍ​ນີ້ວ​ມື​ບໍ່​ເຂົ້າ​ເຖິງ​ໄດ້. ລອງ​ໃໝ່​ອີກ."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"ໝົດເວລາກວດໃບໜ້າແລ້ວ. ກະລຸນາລອງອີກຄັ້ງ."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"ບໍ່ສາມາດເກັບຮັກສາໃບໜ້າໄວ້ໄດ້."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"ຍົກເລີກການດຳເນີນການກັບໃບໜ້າແລ້ວ."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"ຜູ້ໃຊ້ຍົກເລີກການພິສູດຢືນຢັນໃບໜ້າແລ້ວ."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"ມີຄວາມພະຍາຍາມຫຼາຍຄັ້ງເກີນໄປ. ກະລຸນາລອງໃໝ່ໃນພາຍຫຼັງ."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"ມີຄວາມພະຍາຍາມຫຼາຍຄັ້ງເກີນໄປ. ປິດນຳໃຊ້ການກວດສອບຄວາມຖືກຕ້ອງດ້ວຍໃບໜ້າແລ້ວ."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"ລອງອີກຄັ້ງ."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"ການແກ້ໄຂຄ່າສີ"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> off"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"ໃຊ້ປຸ່ມລັດການຊ່ວຍເຂົ້າເຖິງອີກເທື່ອໜຶ່ງເພື່ອຊອກຫາຄຸນສົມບັດການຊ່ວຍເຂົ້າເຖິງໃນປັດຈຸບັນ"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ເລືອກຄຸນສົມບັດທີ່ຈະໃຊ້ເມື່ອທ່ານແຕະປຸ່ມການຊ່ວຍເຂົ້າເຖິງ:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ເພື່ອປ່ຽນຄຸນສົມບັດ, ໃຫ້ແຕະປຸ່ມການຊ່ວຍເຂົ້າເຖິງຄ້າງໄວ້."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"ການຂະຫຍາຍ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index a0015c3..d6869c1 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -130,10 +130,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Kilo problema registruojant „Wi‑Fi“ skambinimą pas operatorių: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"„%s“ „Wi-Fi“ skambinimas"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> „Wi-Fi“ skambinimas"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN skambutis"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN skambutis"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> „Wi-Fi“"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"„Wi-Fi“ skambinimas | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> „VoWifi“"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Išjungta"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Pageidautinas „Wi-Fi“ ryšys"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Pirmenybė mobiliojo ryšio tinklui"</string>
@@ -530,6 +534,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Neatpažinta"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Kontrolinis kodas autentifikuotas"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Veidas autentifikuotas"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Veidas autentifikuotas, paspauskite patvirtinimo mygtuką"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Kontrolinio kodo aparatinė įranga nepasiekiama."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Negalima išsaugoti kontrolinio kodo. Pašalinkite esamą kontrolinį kodą."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Baigėsi kontrolinio kodo nustatymo skirtasis laikas. Bandykite dar kartą."</string>
@@ -566,6 +572,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Baigėsi veido atpaž. skirt. laik. Band. dar kartą."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Nepavyko išsaugoti veido duomenų."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Veido atpažinimo operacija atšaukta."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Veido autentifikavimą atšaukė naudotojas."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Per daug bandymų. Vėliau bandykite dar kartą."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Per daug bandymų. Veido autentifik. išjungtas."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Bandykite dar kartą."</string>
@@ -1664,6 +1671,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Spalvų taisymas"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Pritaikymo neįgaliesiems sparčiuoju klavišu buvo įjungta „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Pritaikymo neįgaliesiems sparčiuoju klavišu buvo išjungta „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Norėdami įjungti dabartinę pritaikymo neįgaliesiems funkciją, dar kartą naudokite spartųjį pritaikymo neįgaliesiems klavišą"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Pasirinkite funkciją, kuri bus naudojama, kai paliesite pritaikymo neįgaliesiems mygtuką:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Jei norite pakeisti funkcijas, palieskite ir palaikykite pritaikymo neįgaliesiems mygtuką."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Didinimas"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index a1aebe1..156a1a9 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -129,10 +129,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Reģistrējot Wi-Fi zvanus pie mobilo sakaru operatora, radās problēma: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Wi-Fi zvani"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi zvani"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN zvans"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN zvans"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi zvani | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Izslēgts"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Vēlams Wi-Fi tīkls"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Vēlams mobilo datu savienojums"</string>
@@ -527,6 +531,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Dati nav atpazīti"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Pirksta nospiedums tika autentificēts."</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Seja autentificēta"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Seja ir autentificēta. Nospiediet pogu Apstiprināt."</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Nospieduma aparatūra nav pieejama."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Pirkstu nospiedumu nevar saglabāt. Lūdzu, noņemiet esošu pirksta nospiedumu."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Pirkstu nospiedumu nolasīšanas aparatūras noildze. Mēģiniet vēlreiz."</string>
@@ -563,6 +569,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Sejas datu nolasīšanas noildze. Mēģiniet vēlreiz."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Sejas datus nevar saglabāt."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Darbība ar sejas datiem atcelta."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Lietotājs atcēla sejas autentificēšanu."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Pārāk daudz mēģinājumu. Vēlāk mēģiniet vēlreiz."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Par daudz mēģinājumu. Sejas atpazīšana atspējota."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Mēģiniet vēlreiz."</string>
@@ -1640,6 +1647,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Krāsu korekcija"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Pieejamības saīsne aktivizēja lietotni <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Pieejamības saīsne deaktivizēja lietotni <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Lai sāktu izmantot pašreizējo pieejamības funkciju, vēlreiz izmantojiet pieejamības saīsni."</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Izvēlieties funkciju, ko izmantot, kad pieskaraties pogai Pieejamība."</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Lai mainītu funkcijas, pieskarieties pogai Pieejamība un turiet to."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Palielinājums"</string>
diff --git a/core/res/res/values-mcc262-mnc02/strings.xml b/core/res/res/values-mcc262-mnc02/strings.xml
deleted file mode 100644
index 2b89401..0000000
--- a/core/res/res/values-mcc262-mnc02/strings.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/**
- * Copyright (c) 2017, Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-     <!-- Do not translate. Template for showing mobile network operator name while WFC is active -->
-     <string-array name="wfcSpnFormats">
-         <item>%s</item>
-         <item>%s Wi-Fi Calling</item>
-     </string-array>
-</resources>
diff --git a/core/res/res/values-mcc302-mnc370/strings.xml b/core/res/res/values-mcc302-mnc370/strings.xml
deleted file mode 100644
index f5b8496..0000000
--- a/core/res/res/values-mcc302-mnc370/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- Template for showing mobile network operator name while WFC is active -->
-    <string-array name="wfcSpnFormats">
-        <item>%s</item>
-        <item>%s Wi-Fi</item>
-    </string-array>
-</resources>
diff --git a/core/res/res/values-mcc302-mnc720/strings.xml b/core/res/res/values-mcc302-mnc720/strings.xml
deleted file mode 100644
index f5b8496..0000000
--- a/core/res/res/values-mcc302-mnc720/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- Template for showing mobile network operator name while WFC is active -->
-    <string-array name="wfcSpnFormats">
-        <item>%s</item>
-        <item>%s Wi-Fi</item>
-    </string-array>
-</resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 0ab31b3..8bca75e 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Проблем при регистрирањето на функцијата „Повици преку Wi‑Fi“ со операторот: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Повикување преку Wi-Fi"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Повици преку Wi-Fi на <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Повик преку WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Повик преку WLAN на <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi на <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Повици преку Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"Глас преку Wi-Fi на <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Исклучено"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Се претпочита Wi-Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Претпочитам мобилен интернет"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Непознат"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Отпечатокот е проверен"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Лицето е проверено"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Лицето е проверено, притиснете го копчето „Потврди“"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Хардвер за отпечаток од прст не е достапен."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Отпечатокот не може да се складира. Отстранете го постоечкиот отпечаток."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Се достигна времето на истекување на отпечатокот. Обидете се повторно."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Истече времето за проверка на лице. Повторен обид."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Лицето не може да се чува."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Операцијата со лице се откажа."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Проверката на лицето е откажана од корисникот."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Премногу обиди. Обидете се повторно подоцна."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Премногу обиди. Проверката на лице е оневозможена."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Обидете се повторно."</string>
@@ -1619,6 +1626,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Корекција на бои"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Кратенката за пристапност ја вклучи <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Кратенката за пристапност ја исклучи <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Повторно употребете ја кратенката за пристапност за да ја стартувате тековната функција за пристапност"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Изберете функција за користење кога ќе го допрете копчето за „Пристапност“."</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"За променување функции, допрете го и задржете го копчето за „Пристапност“."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Зголемување"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index eafd6a4..1efdc72 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"നിങ്ങളുടെ കാരിയർ ഉപയോഗിച്ച് വൈഫൈ കോളിംഗ് രജിസ്‌റ്റർ ചെയ്യുന്നതിൽ പ്രശ്‌നം: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s വൈഫൈ കോളിംഗ്"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> വൈഫൈ കോളിംഗ്"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN കോൾ"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN കോൾ"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> വൈഫൈ"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"വൈഫൈ കോളിംഗ് | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> Voവൈഫൈ"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"ഓഫ്"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"വൈഫൈ തിരഞ്ഞെടുത്തിരിക്കുന്നു"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"മൊബൈൽ ഡാറ്റ ഉപയോഗിക്കാൻ താൽപ്പര്യപ്പെടുന്നു"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"തിരിച്ചറിഞ്ഞില്ല"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"ഫിംഗർപ്രിന്റ് പരിശോധിച്ചുറപ്പിച്ചു"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"മുഖം പരിശോധിച്ചുറപ്പിച്ചു"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"മുഖം പരിശോധിച്ചുറപ്പിച്ചു, സ്ഥിരീകരിക്കുക അമർത്തുക"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ഫിംഗർപ്രിന്റ് ഹാർഡ്‌വെയർ ലഭ്യമല്ല."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"വിരലടയാളം സംഭരിക്കാനാവില്ല. നിലവിലുള്ള വിരലടയാളം നീക്കംചെയ്യുക."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"വിരലടയാളം നൽകേണ്ട സമയം കഴിഞ്ഞു. വീണ്ടും ശ്രമിക്കുക."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"മുഖം നൽകേണ്ട സമയം കഴിഞ്ഞു. വീണ്ടും ശ്രമിക്കുക."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"മുഖം സൂക്ഷിക്കാനാവില്ല."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"മുഖത്തിന്റെ പ്രവർത്തനം റദ്ദാക്കി."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"മുഖം പരിശോധിച്ചുറപ്പിക്കൽ ഉപയോക്താവ് റദ്ദാക്കി."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"നിരവധി തവണ ശ്രമിച്ചു. പിന്നീട് വീണ്ടും ശ്രമിക്കുക."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"നിരവധി തവണ ശ്രമിച്ചു. മുഖം തിരിച്ചറിയൽ പ്രവർത്തനരഹിതമാക്കി."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"വീണ്ടും ശ്രമിക്കുക."</string>
@@ -1617,6 +1624,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"വർണ്ണം ക്രമീകരിക്കൽ"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ഉപയോഗസഹായിക്കുള്ള കുറുക്കുവഴി <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഓൺ ചെയ്തിരിക്കുന്നു"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ഉപയോഗസഹായിക്കുള്ള കുറുക്കുവഴി <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഓഫ് ചെയ്തിരിക്കുന്നു"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"നിലവിലെ ഉപയോഗസഹായി ഫീച്ചർ ആരംഭിക്കാൻ വീണ്ടും ഉപയോഗസഹായി കുറുക്കുവഴി ഉപയോഗിക്കുക"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"നിങ്ങൾ ഉപയോഗസഹായി ബട്ടൺ ടാപ്പുചെയ്യുമ്പോൾ ഉപയോഗിക്കുന്നതിന് ഒരു ഫീച്ചർ തിരഞ്ഞെടുക്കുക:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ഫീച്ചറുകൾ മാറ്റുന്നതിന് ഉപയോഗസഹായി ബട്ടൺ സ്‌പർശിച്ചുപിടിക്കുക."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"മാഗ്നിഫിക്കേഷൻ"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 12e3186..86ae178 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Таны оператор компанийн Wi‑Fi дуудлагыг бүртгэхэд асуудал гарлаа: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Wi-Fi Дуудлага"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi дуудлага"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN дуудлага"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN дуудлага"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"WiFi дуудлага | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Идэвхгүй"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi давуу эрхтэй"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Мобайл давуу эрхтэй"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Таниагүй"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Хурууны хээг нотолсон"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Царайг баталгаажууллаа"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Царайг баталгаажууллаа. Баталгаажуулах товчлуурыг дарна уу"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Хурууны хээний тоног төхөөрөмж бэлэн бус байна."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Хурууны хээг хадгалах боломжгүй байна. Одоо байгаа хурууны хээг арилгана уу."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Хурууны хээ оруулах хугацаа өнгөрсөн байна. Дахин оруулна уу."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Царай таниулах хугацаа дууслаа. Дахин оролдоно уу."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Царайг хадгалах боломжгүй байна."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Царайны үйл ажиллагааг цуцаллаа."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Хэрэглэгч царайгаар баталгаажуулахыг цуцалсан байна."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Хэт олон удаа оролдлоо. Дараа дахин оролдоно уу."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Хэт олон удаа оролдлоо. Царай танилтыг идэвхгүй болголоо."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Дахин оролдоно уу."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Өнгөний засвар"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Хүртээмжийн товчлол <xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г асаасан"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Хүртээмжийн товчлол <xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г унтраасан"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Одоогийн хүртээмжит онцлогийг эхлүүлэхийн тулд нэвтрэлтийн товчлолыг ашиглах"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Хүртээмжийн товчлуурыг товших үедээ ашиглах онцлогийг сонгоно уу:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Онцлогийг өөрчлөхийн тулд Хүртээмжийн товчлуурыг дараад хүлээнэ үү."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Томруулах"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index fe248c1..70ed012 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"तुमच्या या वाहकासह वाय-फाय कॉलिंग नोंदणी करताना समस्या आली आहे:<xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s वाय-फाय कॉलिंग"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> वाय-फाय कॉलिंग"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN कॉल"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN कॉल"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> वाय-फाय"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"वाय-फाय कॉलिंग | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"बंद"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"वाय-फाय अग्रमानांकित"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"प्राधान्य दिलेला मोबाइल"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"ओळखले नाही"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"फिंगरप्रिंट ऑथेंटिकेट केली आहे"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"चेहरा ऑथेंटिकेशन केलेला आहे"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"चेहरा ऑथेंटिकेशन केलेला आहे, कृपया कंफर्म दाबा"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"फिंगरप्रिंट हार्डवेअर उपलब्‍ध नाही."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"फिंगरप्रिंट स्टोअर केले जाऊ शकत नाही. कृपया विद्यमान फिंगरप्रिंट काढा."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"फिंगरप्रिंट टाइमआउट झाले. पुन्हा प्रयत्न करा."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"चेहरा टाइमआउट झाला. पुन्हा प्रयत्न करा."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"चेहरा स्टोअर केला जाऊ शकत नाही."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"चेहरा ऑपरेशन रद्द केले गेले."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"वापरकर्त्याने चेहरा ऑथेंटिकेशन रद्द केले."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"खूप जास्त प्रयत्न केले. नंतर पुन्हा प्रयत्न करा."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"खूप जास्त प्रयत्न केले. चेहरा ऑथेंटिकेशन बंद केले गेले."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"पुन्हा प्रयत्न करा."</string>
@@ -1617,6 +1624,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"रंग सुधारणा"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"प्रवेशयोग्यता शॉर्टकटने <xliff:g id="SERVICE_NAME">%1$s</xliff:g> चालू केली"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"प्रवेशयोग्यता शॉर्टकटने <xliff:g id="SERVICE_NAME">%1$s</xliff:g> बंद केली"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"सध्याचे अॅक्सेसिबिलिटी वैशिष्‍ट्य पुन्हा सुरू करण्‍यासाठी अॅक्सेसिबिलिटी शॉर्टकट वापरा"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"तुम्ही प्रवेशयोग्यता बटण दाबल्यावर वापरण्यासाठी वैशिष्ट्य निवडा:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"वैशिष्ट्ये बदलण्यासाठी, प्रवेशयोग्यता बटणाला स्पर्श करा आणि धरून ठेवा."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"मोठे करणे"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index a813a7b..208fed6 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Terdapat masalah semasa mendaftarkan panggilan Wi-Fi dengan pembawa anda: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Panggilan Wi-Fi"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Panggilan Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Panggilan WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Panggilan WLAN <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Panggilan Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Mati"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi diutamakan"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Mudah alih diutamakan"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Tidak dikenali"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Cap jari disahkan"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Wajah disahkan"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Wajah disahkan, sila tekan sahkan"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Perkakasan cap jari tidak tersedia."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Cap jari tidak dapat disimpan. Sila alih keluar cap jari sedia ada."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Tamat masa cap jari dicapai. Cuba lagi."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Tamat masa wajah dicapai. Cuba lagi."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Wajah tidak dapat disimpan."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Pengendalian wajah dibatalkan."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Pengesahan wajah dibatalkan oleh pengguna."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Terlalu banyak percubaan. Cuba sebentar lagi."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Terlalu banyak percubaan. Pengesahan wajah dilumpuhkan."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Cuba lagi."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Pembetulan Warna"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Pintasan kebolehaksesan menghidupkan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Pintasan Kebolehaksesan mematikan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Gunakan Pintasan Kebolehaksesan sekali lagi untuk memulakan ciri kebolehaksesan semasa"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Pilih ciri yang hendak digunakan apabila anda mengetik butang Kebolehaksesan:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Untuk menukar ciri, sentuh &amp; tahan butang Kebolehaksesan."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Pembesaran"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 812ff75..71dd4b6 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"သင်၏ ဝန်ဆောင်မှုပေးသူဖြင့် Wi‑Fi ခေါ်ဆိုမှုကို မှတ်ပုံတင်ရာတွင် ပြဿနာရှိနေသည်− <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Wi-Fi  ခေါ်ဆိုမှု"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi ခေါ်ဆိုမှု"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN ခေါ်ဆိုမှု"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN ခေါ်ဆိုမှု"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"WiFi ခေါ်ဆိုမှု | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"ပိတ်ထားရသည်"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"ဝိုင်ဖိုင်အား ပိုနှစ်သက်သော"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"မိုဘိုင်းကို အသုံးပြုလိုပါသည်"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"မသိပါ"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"လက်ဗွေကို အထောက်အထား စိစစ်ပြီးပါပြီ"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"မျက်နှာ အထောက်အထားစိစစ်ပြီးပြီ"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"မျက်နှာ အထောက်အထားစိစစ်ပြီးပြီ၊ အတည်ပြုရန်ကို နှိပ်ပါ"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"လက်ဗွေရာ ဟာ့ဒ်ဝဲ မရနိုင်ပါ။"</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"လက်ဗွေရာ သိုလှောင်၍မရပါ။ ကျေးဇူးပြု၍ ရှိပြီးလက်ဗွေရာအား ဖယ်ရှားပါ။"</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"လက်ဗွေရာအချိန်ကုန် သွားပါသည်။ ထပ်မံကြိုးစားပါ။"</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"မျက်နှာ သက်တမ်းကုန်သွားပါပြီ။ ထပ်စမ်းကြည့်ပါ။"</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"မျက်နှာကို သိမ်း၍မရပါ။"</string>
     <string name="face_error_canceled" msgid="283945501061931023">"မျက်နှာ ဆောင်ရွက်ခြင်းကို ပယ်ဖျက်လိုက်ပါပြီ။"</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"အသုံးပြုသူက မျက်နှာအထောက်အထားစိစစ်မှု မလုပ်တော့ပါ။"</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"အကြိမ်များစွာ စမ်းပြီးပါပြီ။ နောက်မှထပ်စမ်းပါ။"</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"အကြိမ်များစွာ စမ်းပြီးပါပြီ။ ပိတ်လိုက်ပါပြီ။"</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"ထပ်စမ်းကြည့်ပါ။"</string>
@@ -1617,6 +1624,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"အရောင်ပြင်ဆင်ခြင်း"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"အများသုံးစွဲနိုင်မှု ဖြတ်လမ်းလင့်ခ်သည် <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ကို ဖွင့်လိုက်ပါသည်"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"အများသုံးစွဲနိုင်မှု ဖြတ်လမ်းလင့်ခ်သည် <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ကို ပိတ်လိုက်ပါသည်"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"လက်ရှိ အသုံးလွယ်ရေး ဝန်ဆောင်မှုကို စတင်ရန် အသုံးလွယ်ရေး ဖြတ်လမ်းလင့်ခ်ကို သုံးပါ"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"အများသုံးစွဲနိုင်မှု ခလုတ်ကို တို့သည့်အခါ အသုံးပြုမည့် ဝန်ဆောင်မှုကို ရွေးချယ်ပါ−"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ဝန်ဆောင်မှုများကို ပြောင်းလဲရန် အများသုံးစွဲနိုင်မှု ခလုတ်ကို တို့၍ ထိထားပါ။"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"ချဲ့ခြင်း"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 439b0de..28e7d33 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Problem med å registrere Wi-Fi-anrop med operatøren din: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Wi-Fi-anrop"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi-anrop"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN-anrop"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN-anrop"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi-anrop | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Av"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi er foretrukket"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Først-på-mobil"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Ikke gjenkjent"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingeravtrykket er godkjent"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Ansiktet er autentisert"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Ansiktet er autentisert. Trykk på Bekreft"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Maskinvare for fingeravtrykk er ikke tilgjengelig."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingeravtrykket kan ikke lagres. Fjern et eksisterende fingeravtrykk."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Tidsavbrudd for fingeravtrykk er nådd. Prøv på nytt."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Tidsavbrudd for ansikt er nådd. Prøv igjen."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Ansiktet kan ikke lagres."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Ansikt-operasjonen ble avbrutt."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Ansiktsautentiseringen ble avbrutt av brukeren."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"For mange forsøk. Prøv igjen senere."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"For mange forsøk. Ansiktsautentisering er slått av."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Prøv igjen."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Fargekorrigering"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Snarveien for tilgjengelighet slo på <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Snarveien for tilgjengelighet slo av <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Bruk tilgjengelighetssnarveien igjen for å starte den nåværende tilgjengelighetsfunksjonen"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Velg en funksjon du vil bruke når du trykker på Tilgjengelighet-knappen:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"For å endre funksjoner, trykk på og hold inne Tilgjengelighet-knappen."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Forstørring"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index d45e28b..875f87d 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"तपाईंको सेवा प्रदायकमार्फत Wi-Fi कलिङ सुविधा दर्ता गर्ने क्रममा देखिएको समस्या: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Wi-Fi कलिङ"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi कलिङ"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN कल"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN कल"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wifi कलिङ | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"निष्क्रिय"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi मनपराइयो"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"रूचाइएको मोबाइल"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"पहिचान भएन"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"फिंगरप्रिन्ट प्रमाणीकरण गरियो"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"अनुहार प्रमाणीकरण गरियो"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"अनुहार प्रमाणीकरण गरियो, कृपया पुष्टि गर्नुहोस् थिच्नुहोस्"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"औँठाछाप हार्डवेयर उपलब्ध छैन।"</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"औँठाछाप भण्डारण गर्न सकिँदैन। कृपया अवस्थित औठाछाप हटाउनुहोस्।"</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"औँठाछापको समय सकिएको छ। फेरि प्रयास गर्नुहोस्।"</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"अनुहारको समय सकिएको छ। फेरि प्रयास गर्नुहोस्‌।"</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"अनुहार भण्डारण गर्न सकिँदैन।"</string>
     <string name="face_error_canceled" msgid="283945501061931023">"अनुहार पहिचान रद्द गरियो।"</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"प्रयोगकर्ताले अनुहार प्रमाणीकरण रद्द गर्नु भयो।"</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"धेरैपटक प्रयासहरू भए। पछि फेरि प्रयास गर्नुहोस्‌।"</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"अत्यधिक धेरैपटक गलत प्रयासहरू भए। अनुहार प्रमाणिकरणलाई असक्षम पारियो।"</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"फेरि प्रयास गर्नुहोस्।"</string>
@@ -1622,6 +1629,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"रङ सच्याउने सुविधा"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"पहुँचको सर्टकटले <xliff:g id="SERVICE_NAME">%1$s</xliff:g> लाई सक्रिय पार्‍यो"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"पहुँचको सर्टकटले <xliff:g id="SERVICE_NAME">%1$s</xliff:g> लाई निष्क्रिय पार्‍यो"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"हालको पहुँचसम्बन्धी सुविधा प्रयोग गर्न फेरि पहुँचसम्बन्धी सर्टकट प्रयोग गर्नुहोस्"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"तपाईंले पहुँच सम्बन्धी बटनलाई ट्याप गर्दा प्रयोग गर्नुपर्ने सुविधा रोज्नुहोस्:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"सुविधाहरूलाई बदल्न, पहुँच सम्बन्धी बटनलाई छोएर थिची राख्नुहोस्।"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"म्याग्निफिकेसन"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index df152b2..b95ba19 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -79,7 +79,7 @@
     <string name="CLIRPermanent" msgid="3377371145926835671">"U kunt de instelling voor de beller-ID niet wijzigen."</string>
     <string name="RestrictedOnDataTitle" msgid="5221736429761078014">"Geen service voor mobiele data"</string>
     <string name="RestrictedOnEmergencyTitle" msgid="6855466023161191166">"Noodoproepen niet beschikbaar"</string>
-    <string name="RestrictedOnNormalTitle" msgid="3179574012752700984">"Geen service voor spraakoproepen"</string>
+    <string name="RestrictedOnNormalTitle" msgid="3179574012752700984">"Geen belservice"</string>
     <string name="RestrictedOnAllVoiceTitle" msgid="8037246983606545202">"Geen spraakservice of noodoproepen"</string>
     <string name="RestrictedStateContent" msgid="6538703255570997248">"Tijdelijk uitgeschakeld door je provider"</string>
     <string name="RestrictedStateContentMsimTemplate" msgid="673416791370248176">"Tijdelijk uitgeschakeld door je provider voor sim <xliff:g id="SIMNUMBER">%d</xliff:g>"</string>
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Probleem bij registratie van Bellen via wifi bij je provider: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"Bellen via wifi van %s"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Bellen via wifi van <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Bellen via WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Bellen via WLAN van <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wifi van <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Bellen via wifi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi van <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Uit"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Voorkeur voor wifi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Voorkeur voor mobiel"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Niet herkend"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Vingerafdruk geverifieerd"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Gezicht geverifieerd"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Gezicht geverifieerd. Druk op Bevestigen."</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware voor vingerafdruk niet beschikbaar."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Vingerafdruk kan niet worden opgeslagen. Verwijder een bestaande vingerafdruk."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Time-out bereikt voor vingerafdruk. Probeer het opnieuw."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Time-out voor gezicht bereikt. Probeer opnieuw."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Gezicht kan niet worden opgeslagen."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Bewerking voor gezichtsherkenning geannuleerd."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Gezichtsverificatie geannuleerd door gebruiker."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Te veel pogingen. Probeer het later opnieuw."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Te veel pogingen. Gezichtsherkenning inactief."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Probeer het opnieuw."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Kleurcorrectie"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"\'Snelle link voor toegankelijkheid\' heeft <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ingeschakeld"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"\'Snelle link voor toegankelijkheid\' heeft <xliff:g id="SERVICE_NAME">%1$s</xliff:g> uitgeschakeld"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Gebruik de snelkoppeling voor toegankelijkheid nogmaals om de huidige toegankelijkheidsfunctie te starten"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Kies een functie om te gebruiken wanneer je op de knop Toegankelijkheid tikt:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Als je functies wilt wijzigen, tik je op de knop Toegankelijkheid en houd je deze vast."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Vergroting"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 78566da..9d3fa8e 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"ଆପଣଙ୍କ କେରିଅର୍ ସହିତ ୱାଇ-ଫାଇ କଲ୍ କରିବା ପାଇଁ ପଞ୍ଜୀକରଣ କରିବାରେ ସମସ୍ୟା: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s ୱାଇ-ଫାଇ କଲିଙ୍ଗ"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> ୱାଇ-ଫାଇ କଲିଂ"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN କଲ୍‍"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN କଲ୍‍"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> ୱାଇ-ଫାଇ"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"ୱାଇଫାଇ କଲିଂ | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"ଅଫ୍"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"ପସନ୍ଦ କରାଯାଇଥିବା ୱାଇ-ଫାଇ"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"ପସନ୍ଦର ମୋବାଇଲ୍‌"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"ଚିହ୍ନଟ ହେଲାନାହିଁ"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ପ୍ରମାଣୀକୃତ ହେଲା"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"ମୁହଁ ଚିହ୍ନଟ ହୋଇଛି"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"ମୁହଁ ଚିହ୍ନଟ ହୋଇଛି, ଦୟାକରି ସୁନିଶ୍ଚିତ ଦବାନ୍ତୁ"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ହାର୍ଡୱେର୍‍ ଉପଲବ୍ଧ ନାହିଁ।"</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ଷ୍ଟୋର୍‍ କରାଯାଇପାରିବ ନାହିଁ। ଦୟାକରି ପୂର୍ବରୁ ଥିବା ଆଙ୍ଗୁଠି ଚିହ୍ନକୁ ବାହାର କରିଦିଅନ୍ତୁ।"</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"ଆଙ୍ଗୁଠି ଚିହ୍ନର ସମୟ ଶେଷ ହେଲା । ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"ଫେସ୍‍ର ସମୟସୀମା ସରିଗଲା। ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"ଫେସ୍‍ ମେମୋରୀରେ ଷ୍ଟୋର୍‍ କରାଯାଇପାରିବ ନାହିଁ।"</string>
     <string name="face_error_canceled" msgid="283945501061931023">"ଫେସ୍‍ର ଅପରେଶନ୍‍ କ୍ୟାନ୍ସଲ୍‍ ହୋ‍ଇଗଲା"</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"ଉପଯୋଗକର୍ତ୍ତା ମୁହଁ ଚିହ୍ନଟକରଣ ବାତିଲ୍‌ କରିଛନ୍ତି।"</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"ବାରମ୍ବାର ଚେଷ୍ଟା। ପରେ ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"ବାରମ୍ବାର ଚେଷ୍ଟା। ଫେସ୍‍ ପ୍ରମାଣୀକରଣ ଅକ୍ଷମ କରାଗଲା।"</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
@@ -1617,6 +1624,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"ରଙ୍ଗ ସଂଶୋଧନ"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ଆକ୍ସେସିବିଲିଟୀ ଶର୍ଟକଟ୍‍ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ଅନ୍‍ କରାଯାଇଛି"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ଆକ୍ସେସିବିଲିଟୀ ଶର୍ଟକଟ୍‍ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ଅଫ୍‍ କରାଯାଇଛି"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"ବର୍ତ୍ତମାନର ଆକ୍ସେସିବିଲିଟୀ ବୈଶିଷ୍ଟ୍ୟ ଆରମ୍ଭ କରିବାକୁ ପୁଣି ଆକ୍ସେସିବିଲିଟୀ ସର୍ଟ୍‍କର୍ଟ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ଆପଣ ଆକ୍ସେସବିଲିଟି ବଟନ୍‍ ଟାପ୍‍ କରିବା ବେଳେ ଏକ ବୈଶିଷ୍ଟ୍ୟ ବ୍ୟବହାର କରିବାକୁ ବାଛନ୍ତୁ:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ବୈଶିଷ୍ଟ୍ୟ ବଦଳାଇବାକୁ, ଆକ୍ସେସବିଲିଟି ବଟନ୍‍ ସ୍ପର୍ଶ କରନ୍ତୁ ଓ ଧରିରଖନ୍ତୁ।"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"ମ୍ୟାଗ୍ନିଫିକେସନ୍‍"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index bb38c88..6e615a8 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"ਤੁਹਾਡੇ ਕੈਰੀਅਰ ਨਾਲ ਵਾਈ-ਫਾਈ ਕਾਲਿੰਗ ਨੂੰ ਰਜਿਸਟਰ ਕਰਨ ਵਿੱਚ ਸਮੱਸਿਆ ਆਈ: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s ਵਾਈ-ਫਾਈ ਕਾਲਿੰਗ"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> ਵਾਈ-ਫਾਈ ਕਾਲਿੰਗ"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN ਕਾਲ"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN ਕਾਲ"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> ਵਾਈ-ਫਾਈ"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"ਵਾਈ-ਫਾਈ ਕਾਲਿੰਗ | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"ਬੰਦ"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"ਤਰਜੀਹੀ ਵਾਈ-ਫਾਈ"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"ਮੋਬਾਈਲ ਨੂੰ ਤਰਜੀਹ ਹੈ"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"ਪਛਾਣ ਨਹੀਂ ਹੋਈ"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਪ੍ਰਮਾਣਿਤ ਹੋਇਆ"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"ਚਿਹਰਾ ਪੁਸ਼ਟੀਕਰਨ"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"ਚਿਹਰਾ ਪੁਸ਼ਟੀਕਰਨ, ਕਿਰਪਾ ਕਰਕੇ \'ਪੁਸ਼ਟੀ ਕਰੋ\' ਦਬਾਓ"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਹਾਰਡਵੇਅਰ ਉਪਲਬਧ ਨਹੀਂ।"</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸਟੋਰ ਨਹੀਂ ਕੀਤਾ ਸਕਦਾ। ਕਿਰਪਾ ਕਰਕੇ ਇੱਕ ਮੌਜੂਦਾ ਫਿੰਗਰਪ੍ਰਿੰਟ ਹਟਾਓ।"</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਦਾ ਸਮਾਂ ਸਮਾਪਤ ਹੋ ਗਿਆ ਹੈ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"ਚਿਹਰਾ ਪਛਾਣਨ ਦਾ ਸਮਾਂ ਸਮਾਪਤ ਹੋਇਆ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"ਚਿਹਰੇ ਦੀ ਜਾਣਕਾਰੀ ਨੂੰ ਸਟੋਰ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ।"</string>
     <string name="face_error_canceled" msgid="283945501061931023">"ਚਿਹਰਾ ਪਛਾਣਨ ਦੀ ਪ੍ਰਕਿਰਿਆ ਰੱਦ ਕੀਤੀ ਗਈ।"</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"ਵਰਤੋਂਕਾਰ ਵੱਲੋਂ ਚਿਹਰਾ ਪੁਸ਼ਟੀਕਰਨ ਨੂੰ ਰੱਦ ਕੀਤਾ ਗਿਆ।"</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"ਹੱਦੋਂ ਵੱਧ ਕੋਸ਼ਿਸ਼ਾਂ। ਬਾਅਦ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"ਹੱਦੋਂ ਵੱਧ ਕੋਸ਼ਿਸ਼ਾਂ। ਚਿਹਰਾ ਪ੍ਰਮਾਣੀਕਰਨ ਬੰਦ ਹੈ।"</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
@@ -1617,6 +1624,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"ਰੰਗ ਸੁਧਾਈ"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ਪਹੁੰਚਯੋਗਤਾ ਸ਼ਾਰਟਕੱਟ ਨੇ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਨੂੰ ਚਾਲੂ ਕੀਤਾ"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ਪਹੁੰਚਯੋਗਤਾ ਸ਼ਾਰਟਕੱਟ ਨੇ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਨੂੰ ਬੰਦ ਕੀਤਾ"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"ਮੌਜੂਦਾ ਪਹੁੰਚਯੋਗਤਾ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਸ਼ੁਰੂ ਕਰਨ ਲਈ \'ਪਹੁੰਚਯੋਗਤਾ ਸ਼ਾਰਟਕੱਟ\' ਦੀ ਦੁਬਾਰਾ ਵਰਤੋਂ ਕਰੋ"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ਤੁਹਾਡੇ ਵੱਲੋਂ ਪਹੁੰਚਯੋਗਤਾ ਬਟਨ ਨੂੰ ਟੈਪ ਕੀਤੇ ਜਾਣ \'ਤੇ ਵਰਤਣ ਲਈ ਕੋਈ ਵਿਸ਼ੇਸ਼ਤਾ ਚੁਣੋ:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਬਦਲਣ ਲਈ, ਪਹੁੰਚਯੋਗਤਾ ਬਟਨ ਨੂੰ ਸਪੱਰਸ਼ ਕਰੋ ਅਤੇ ਦਬਾਈ ਰੱਖੋ।"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"ਵੱਡਦਰਸ਼ੀਕਰਨ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index d59b138..81a869a 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -130,10 +130,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Podczas rejestrowania połączeń przez Wi-Fi u operatora wystąpił problem: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"Połączenia przez Wi-Fi (%s)"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g>, połączenia przez Wi-Fi"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Połączenie przez WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g>, połączenie przez WLAN"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g>, Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Połączenia przez Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g>, VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Wył."</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Preferuj Wi-Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Preferowane komórkowe"</string>
@@ -530,6 +534,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Nie rozpoznano"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Uwierzytelniono odciskiem palca"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Twarz rozpoznana"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Twarz rozpoznana, kliknij Potwierdź"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Czytnik linii papilarnych nie jest dostępny."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Nie można zapisać odcisku palca. Usuń istniejący odcisk palca."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Osiągnięto limit czasu odczytu linii papilarnych. Spróbuj ponownie."</string>
@@ -566,6 +572,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Upłynął limit czasu analizy twarzy. Spróbuj ponownie."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Nie można zapisać informacji o twarzy."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Analiza twarzy została anulowana."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Użytkownik anulował uwierzytelnianie twarzą."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Zbyt wiele prób. Spróbuj ponownie później."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Zbyt wiele prób. Wyłączono uwierzytelnianie za pomocą twarzy."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Spróbuj ponownie."</string>
@@ -1664,6 +1671,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Korekcja kolorów"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Skrót ułatwień dostępu wyłączył usługę <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Skrót ułatwień dostępu wyłączył usługę <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Użyj ponownie skrótu ułatwień dostępu, by uruchomić bieżące ułatwienie dostępu"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Wybierz funkcję używaną po kliknięciu przycisku ułatwień dostępu."</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Aby zmienić funkcje, kliknij i przytrzymaj przycisk ułatwień dostępu."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Powiększenie"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 48302a0..5ac7c2e 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Ocorreu um problema ao registrar a chamada no Wi‑Fi junto à sua operadora: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s chamada Wi-Fi"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Chamada no Wi-Fi de <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Chamada por WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Chamada por WLAN de <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi de <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Chamada no Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi de <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Desativado"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi preferido"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Preferência pela rede móvel"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Não reconhecido"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Impressão digital autenticada"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Rosto autenticado"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Rosto autenticado, pressione \"Confirmar\""</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware de impressão digital não disponível."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Não foi possível armazenar a impressão digital. Remova uma impressão digital já existente."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Tempo máximo para captura da impressão digital atingido. Tente novamente."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Tempo máx. p/ captura facial atingido. Tente novamente."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Não é possível armazenar um rosto."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Operação facial cancelada."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Autenticação facial cancelada pelo usuário."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Excesso de tentativas. Tente novamente mais tarde."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Excesso de tentativas. Autenticação facial desat."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Tente novamente."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Correção de cor"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"O atalho de acessibilidade ativou o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"O atalho de acessibilidade desativou o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Use o atalho de acessibilidade novamente para iniciar o recurso de acessibilidade atual"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Escolha um recurso a ser usado ao tocar no botão Acessibilidade:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Para alterar os recursos, mantenha o botão Acessibilidade pressionado."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ampliação"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 3f02828..52f067f 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Ocorreu um problema ao registar a funcionalidade Chamadas Wi-Fi junto do seu operador: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"Chamadas por Wi-Fi da %s"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Chamadas Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Chamada WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Chamada WLAN <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Chamadas Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Desativado"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Rede Wi-Fi preferida"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Preferência pela rede móvel"</string>
@@ -419,11 +423,11 @@
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"alterar as suas definições de áudio"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Permite que a aplicação modifique definições de áudio globais, tais como o volume e qual o altifalante utilizado para a saída de som."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"gravar áudio"</string>
-    <string name="permdesc_recordAudio" msgid="4245930455135321433">"Esta aplicação pode gravar áudio através do microfone a qualquer momento."</string>
+    <string name="permdesc_recordAudio" msgid="4245930455135321433">"Esta aplicação pode gravar áudio através do microfone em qualquer altura."</string>
     <string name="permlab_sim_communication" msgid="2935852302216852065">"enviar comandos para o SIM"</string>
     <string name="permdesc_sim_communication" msgid="5725159654279639498">"Permite que a aplicação envie comandos para o SIM. Esta ação é muito perigosa."</string>
     <string name="permlab_camera" msgid="3616391919559751192">"tirar fotos e vídeos"</string>
-    <string name="permdesc_camera" msgid="5392231870049240670">"Esta aplicação pode tirar fotos e gravar vídeos através da câmara a qualquer momento."</string>
+    <string name="permdesc_camera" msgid="5392231870049240670">"Esta aplicação pode tirar fotos e gravar vídeos através da câmara em qualquer altura."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"controlar vibração"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Permite à aplicação controlar o vibrador."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"marcar números de telefone diretamente"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Não reconhecido."</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"A impressão digital foi autenticada."</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Rosto autenticado."</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Rosto autenticado. Prima Confirmar."</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware de impressão digital não disponível."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Não é possível armazenar a impressão digital. Remova uma impressão digital existente."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Foi atingido o limite de tempo da impressão digital. Tente novamente."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Limite de tempo de rosto atingido. Tente novamente."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Não é possível armazenar o rosto."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Operação de rosto cancelada."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Autenticação facial cancelada pelo utilizador."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Demasiadas tentativas. Tente novamente mais tarde."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Demasiadas tentativas. Autenticação facial desativada."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Tente novamente."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Correção da cor"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"O Atalho de acessibilidade ativou o serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"O Atalho de acessibilidade desativou o serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Utilize novamente o atalho de acessibilidade para iniciar a funcionalidade de acessibilidade atual."</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Escolha uma funcionalidade para utilizar quando tocar no botão Acessibilidade:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Para alterar as funcionalidades, toque sem soltar no botão Acessibilidade."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ampliação"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 48302a0..5ac7c2e 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Ocorreu um problema ao registrar a chamada no Wi‑Fi junto à sua operadora: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s chamada Wi-Fi"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Chamada no Wi-Fi de <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Chamada por WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Chamada por WLAN de <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi de <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Chamada no Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi de <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Desativado"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi preferido"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Preferência pela rede móvel"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Não reconhecido"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Impressão digital autenticada"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Rosto autenticado"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Rosto autenticado, pressione \"Confirmar\""</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware de impressão digital não disponível."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Não foi possível armazenar a impressão digital. Remova uma impressão digital já existente."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Tempo máximo para captura da impressão digital atingido. Tente novamente."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Tempo máx. p/ captura facial atingido. Tente novamente."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Não é possível armazenar um rosto."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Operação facial cancelada."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Autenticação facial cancelada pelo usuário."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Excesso de tentativas. Tente novamente mais tarde."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Excesso de tentativas. Autenticação facial desat."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Tente novamente."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Correção de cor"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"O atalho de acessibilidade ativou o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"O atalho de acessibilidade desativou o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Use o atalho de acessibilidade novamente para iniciar o recurso de acessibilidade atual"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Escolha um recurso a ser usado ao tocar no botão Acessibilidade:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Para alterar os recursos, mantenha o botão Acessibilidade pressionado."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ampliação"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 1c95559..0c945f7 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -129,10 +129,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"A apărut o problemă la înregistrarea apelării prin Wi‑Fi la operatorul dvs.: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"Apelare prin Wi-Fi %s"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Apelare prin Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Apel WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Apel WLAN <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Apelare prin Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Dezactivată"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Se preferă conexiunea Wi-Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Se preferă datele mobile"</string>
@@ -527,6 +531,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Nu este recunoscut"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Amprentă autentificată"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Chip autentificat"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Chip autentificat, apăsați Confirmați"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware-ul pentru amprentă nu este disponibil."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Amprenta nu poate fi stocată. Eliminați o amprentă existentă."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Timpul pentru amprentare a expirat. Încercați din nou."</string>
@@ -563,6 +569,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Timpul pentru reunoaștere facială a expirat. Încercați din nou."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Chipul nu poate fi stocat."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Operațiunea privind chipul a fost anulată."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Autentificarea chipului anulată de utilizator."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Prea multe încercări. Reîncercați mai târziu."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Prea multe încercări. Autentificarea facială este dezactivată."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Încercați din nou."</string>
@@ -1640,6 +1647,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Corecția culorii"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Comanda rapidă de accesibilitate a activat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Comanda rapidă de accesibilitate a dezactivat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Folosiți din nou comanda rapidă Accesibilitate pentru a porni funcția de accesibilitate prezentă"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Alegeți o funcție pe care să o folosiți când atingeți butonul Accesibilitate:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Pentru a schimba funcțiile, atingeți lung butonul Accesibilitate."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Mărire"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index c14bce4..fd70e9c 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -130,10 +130,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Ошибка подключения функции \"Звонки по Wi-Fi\" через вашего оператора: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"Звонки по Wi-Fi (%s)"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Звонки по Wi-Fi"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Вызов WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> Вызов WLAN"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Звонки по Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Отключено"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Приоритет Wi-Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Приоритет мобильного Интернета"</string>
@@ -530,6 +534,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Не распознано"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Отпечаток пальца проверен"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Лицо распознано"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Лицо распознано, нажмите кнопку \"Подтвердить\""</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Сканер недоступен"</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Чтобы сохранить новый отпечаток, удалите существующий."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Превышено время ожидания. Повторите попытку."</string>
@@ -566,6 +572,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Превышено время ожидания. Повторите попытку."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Невозможно сохранить распознанное лицо"</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Распознавание отменено"</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Распознавание лица отменено пользователем."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Слишком много попыток. Повторите позже."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Слишком много попыток. Сканер отключен."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Попробуйте ещё раз"</string>
@@ -1664,6 +1671,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Коррекция цвета"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Сервис <xliff:g id="SERVICE_NAME">%1$s</xliff:g> включен"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Сервис <xliff:g id="SERVICE_NAME">%1$s</xliff:g> отключен"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Чтобы активировать выбранные специальные возможности, воспользуйтесь быстрым включением ещё раз"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Выберите функцию, которая запускается при нажатии кнопки специальных возможностей:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Чтобы изменить функцию, удерживайте кнопку специальных возможностей."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Увеличение"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 0f353f2..3bd8ceb 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"ඔබගේ වාහකය සමඟ Wi-Fi ඇමතුම් ලියාපදිංචි කිරීම නිකුත් කරන්න: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Wi-Fi අමතමින්"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi ඇමතුම්"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN ඇමතුම"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN ඇමතුම්"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"WiFi ඇමතුම් | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"ක්‍රියාවිරහිතයි"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi වඩා කැමතියි"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"ජංගම කැමතියි"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"හඳුනා නොගන්නා ලදී"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"ඇඟිලි සලකුණ සත්‍යාපනය කරන ලදී"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"මුහුණ සත්‍යාපනය කරන ලදී"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"මුහුණ සත්‍යාපනය කරන ලදී, කරුණාකර තහවුරු කරන්න ඔබන්න"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ඇඟිලි සලකුණු දෘඪාංගය ලද නොහැකිය."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"ඇඟිලි සලකුණ ගබඩා කළ නොහැක. දැනට පවතින ඇඟිලි සලකුණක් ඉවත් කරන්න."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"ඇඟිලි සලකුණු කාල නිමාව ළඟා විය. නැවත උත්සාහ කරන්න."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"මුහුණු කාල නිමාව ළඟා විය. නැවත උත්සාහ කරන්න."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"මුහුණ ගබඩා කළ නොහැක."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"මුහුණු මෙහෙයුම අවලංගු කරන ලදී."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"පරිශීලකයා විසින් මුහුණ සත්‍යාපනය අවලංගු කරන ලදී."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"උත්සාහයන් ඉතා වැඩි ගණනකි. පසුව නැවත උත්සාහ කරන්න."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"උත්සාහයන් ඉතා වැඩි ගණනකි. මුහුණු සත්‍යාපනය අබල කරන ලදී."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"නැවත උත්සාහ කරන්න."</string>
@@ -1618,6 +1625,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"වර්ණ නිවැරදි කිරීම"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ප්‍රවේශ්‍යතා කෙටි මග <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ක්‍රියාත්මක කරන ලදී"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ප්‍රවේශ්‍යතා කෙටි මග <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ක්‍රියාවිරහිත කරන ලදී"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"වර්තමාන ප්‍රවේශ්‍යතා විශේෂංගය ආරම්භ කිරීම සඳහා ප්‍රවේශ්‍යතා කෙටි මග භාවිතා කරන්න"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ඔබ ප්‍රවේශ්‍යතා බොත්තම තට්ටු කරන විට භාවිතා කිරීමට අංගයක් තෝරාගන්න:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"අංග වෙනස් කිරීමට ප්‍රවේශ්‍යතා බොත්තම ස්පර්ශ කර අල්ලා ගෙන සිටින්න."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"විශාලනය"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 3109702..c0981ce 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -130,10 +130,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Pri registrácii volania cez Wi‑Fi u operátora nastala chyba <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"Volanie siete Wi‑Fi %s"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> volanie cez Wi-Fi"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Volanie cez WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> volanie cez WLAN"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Volanie cez WiFi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Vypnuté"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Preferovať Wi‑Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Preferovať mobilné spojenie"</string>
@@ -530,6 +534,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Nerozpoznané"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Odtlačok bol overený"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Tvár bola overená"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Tvár bola overená, stlačte tlačidlo potvrdenia"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardvér na snímanie odtlačku prsta nie je k dispozícii"</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Odtlačok prsta nie je možné uložiť. Odstráňte existujúci odtlačok."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Časový limit rozpoznania odtlačku vypršal. Skúste to znova."</string>
@@ -566,6 +572,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Limit rozpoznania tváre vypršal. Skúste to znova."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Tvár sa nedá uchovať."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Operácia týkajúca sa tváre bola zrušená"</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Overenie tváre bolo zrušené používateľom."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Príliš veľa pokusov. Skúste to znova neskôr."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Príliš veľa pokusov. Overenie tváre je zakázané."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Skúste to znova."</string>
@@ -1664,6 +1671,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Úprava farieb"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Skratka dostupnosti zapla službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Skratka dostupnosti vypla službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Znova použite skratku dostupnosti, čím sprístupníte aktuálnu funkciu dostupnosti"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Klepnutím na tlačidlo dostupnosti vyberte požadovanú funkciu:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Ak chcete zmeniť funkcie, klepnite na tlačidlo dostupnosti a podržte ho"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Priblíženie"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 4575d00..261e6ed 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -130,10 +130,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Težava pri registriranju klicanja prek Wi-Fi-ja pri operaterju: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"Klicanje prek Wi-Fi-ja (%s)"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Klicanje prek Wi-Fi-ja operaterja <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Klic prek omrežja WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Klic prek omrežja WLAN operaterja <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi operaterja <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Klicanje prek WiFi-ja | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"Govor prek Wi-Fi-ja operaterja <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Izklopljeno"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Prednostno Wi-Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Prednostno mobilno"</string>
@@ -530,6 +534,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Ni prepoznano"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Pristnost prstnega odtisa je preverjena"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Pristnost obraza je potrjena"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Pristnost obraza je preverjena. Pritisnite gumb »Potrdi«."</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Strojna oprema za prstne odtise ni na voljo."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Prstnega odtisa ni mogoče shraniti. Odstranite obstoječi prstni odtis."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Dosežena časovna omejitev za prstni odtis. Poskusite znova."</string>
@@ -566,6 +572,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Dosežena časovna omejitev za obraz. Poskusite znova."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Obraza ni mogoče shraniti."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Dejanje z obrazom je bilo preklicano."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Preverjanje pristnosti obraza preklical uporabnik"</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Preveč poskusov. Poskusite znova pozneje."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Preveč poskusov. Preverjanje pristnosti obraza je onemogočeno."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Poskusite znova."</string>
@@ -1664,6 +1671,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Popravljanje barv"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Bližnjica funkcij za ljudi s posebnimi potrebami je vklopila <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Bližnjica funkcij za ljudi s posebnimi potrebami je izklopila <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Če želite zagnati trenutno funkcijo za ljudi s posebnimi potrebami, znova uporabite bližnjico funkcij za ljudi s posebnimi potrebami"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Izberite funkcijo, ki jo želite uporabljati, ko se dotaknete gumba »Dostopnost«:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Če želite spremeniti funkcije, se dotaknite gumba »Dostopnost« in ga pridržite."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Povečava"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 1149421..4b6cb09 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Problem gjatë regjistrimit të telefonatave me Wi‑Fi me operatorin tënd celular: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"Telefonatat me Wi-Fi nga %s"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Telefonatë me Wi-Fi në <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Telefonatë me WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Telefonatë me WLAN në <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi në <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Telefonatë me Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi në <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Çaktivizuar"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Preferohet Wi-Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Preferohet rrjeti celular"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Nuk njihet"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Gjurma e gishtit u vërtetua"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Fytyra u vërtetua"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Fytyra u vërtetua, shtyp \"Konfirmo\""</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardueri i gjurmës së gishtit nuk mundësohet."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Gjurma e gishtit nuk mund të ruhet. Hiq një gjurmë gishti ekzistuese."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Koha e veprimit për gjurmën e gishtit skadoi. Provo përsëri."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Mbaroi afati për fytyrën. Provo sërish."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Fytyra nuk mund të ruhet."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Veprimi me fytyrën u anulua."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Vërtetimi me fytyrë u anulua nga përdoruesi."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Shumë përpjekje. Provo sërish më vonë."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Shumë përpjekje. Vërtetimi për fytyrën joaktiv."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Provo sërish."</string>
@@ -1617,6 +1624,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Korrigjimi i ngjyrës"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Shkurtorja e qasshmërisë e aktivizoi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Shkurtorja e qasshmërisë e çaktivizoi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Përdor përsëri \"Shkurtoren e qasshmërisë\" për të nisur funksionin aktual të qasshmërisë"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Zgjidh një funksion për ta përdorur kur troket butonin e \"Qasshmërisë\":"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Për të ndryshuar funksionet, prek dhe mbaj butonin e \"Qasshmërisë\"."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Zmadhimi"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 7536531..449fdfc 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -129,10 +129,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Проблем у вези са регистровањем позивања преко Wi‑Fi-ја код мобилног оператера: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"Wi-Fi позивање преко оператера %s"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> позивање преко Wi-Fi-ја"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN позив"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN позив"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Позивање преко Wi-Fi-ја | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Искључено"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Предност има Wi-Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Желим мобилне податке"</string>
@@ -527,6 +531,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Није препознато"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Отисак прста је потврђен"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Лице је потврђено"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Лице је потврђено. Притисните Потврди"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Хардвер за отиске прстију није доступан."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Није могуће сачувати отисак прста. Уклоните неки од постојећих отисака прстију."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Временско ограничење за отисак прста је истекло. Пробајте поново."</string>
@@ -563,6 +569,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Истекло је време за проверу лица. Пробајте поново."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Није могуће сачувати лице."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Обрада лица је отказана."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Корисник је отказао потврду лица."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Превише покушаја. Пробајте поново касније."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Више покушаја. Потврда идентитета је онемогућена."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Пробајте поново."</string>
@@ -1640,6 +1647,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Корекција боја"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Пречица за приступачност је укључила услугу <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Пречица за приступачност је искључила услугу <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Употребите поново пречицу за приступачност да бисте покренули актуелну функцију приступачности"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Изаберите функцију која ће се користити када додирнете дугме за приступачност:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Притисните и задржите дугме за приступачност да бисте мењали функције."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Увећање"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 31bb349..9f46514 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Följande fel uppstod när Wi-Fi-samtal skulle registreras hos operatören: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Wi-Fi-samtal"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Wi-Fi-samtal via <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN-samtal"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"WLAN-samtal via <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi via <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi-samtal | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi via <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Av"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi i första hand"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Använd mobildata"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Identifierades inte"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingeravtrycket har autentiserats"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Ansiktet har autentiserats"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Ansiktet har autentiserats. Tryck på Bekräfta"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Det finns ingen maskinvara för fingeravtryck."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingeravtrycket kan inte lagras. Ta bort ett befintligt fingeravtryck."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Tidsgränsen för fingeravtrycket har uppnåtts. Försök igen."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Tidsgränsen för ansikte har nåtts. Försök igen."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Det gick inte att lagra ansiktet."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Ansiktsåtgärden har avbrutits."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Autentiseringen av ansiktet avbröts av användaren."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Du har gjort för många försök. Försök igen senare."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"För många försök. Ansiktsautentisering inaktiverad"</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Försök igen."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Färgkorrigering"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> aktiverades av Aktivera tillgänglighet snabbt"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> inaktiverades av Aktivera tillgänglighet snabbt"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Använd Aktivera tillgänglighet snabbt en gång till om du vill aktivera tillgänglighetsfunktionen i fråga"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Välj en funktion som ska användas när du trycker på tillgänglighetsknappen:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Tryck länge på tillgänglighetsknappen för att ändra funktioner."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Förstoring"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 3d26224..b0858dc 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -128,8 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Tatizo limetokea wakati wa kuisajili huduma ya kupiga simu kupitia Wi‑Fi kwa mtoa huduma wako: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for wfcSpnFormats:0 (6830082633573257149) -->
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Kupiga Simu Kupitia Wi-Fi ya <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Simu ya WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Simu ya WLAN ya <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi ya <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Kupiga Simu kupitia WiFi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi ya <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Imezimwa"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi inapedelewa"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Mtandao wa simu unapendelewa"</string>
@@ -522,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Hayatambuliki"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Imethibitisha alama ya kidole"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Uso umethibitishwa"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Uso umethibitishwa, tafadhali bonyeza thibitisha"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Maunzi ya kitambulisho hayapatikani."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Kitambulisho hakiwezi kuhifadhiwa. Tafadhali ondoa kitambulisho kilichopo."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Muda wa kitambulisho umekwisha. Jaribu tena."</string>
@@ -558,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Muda wa kutambua uso umeisha. Jaribu tena."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Huwezi kuhifadhi uso."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Utendaji wa kitambulisho umeghairiwa."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Uthibitishaji wa uso umeghairiwa na mtumiaji."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Umejaribu mara nyingi mno. Jaribu tena baadaye."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Umejaribu mara nyingi mno. Kitambuzi cha uso kimezimwa."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Jaribu tena."</string>
@@ -1614,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Usahihishaji wa rangi"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Njia ya mkato ya zana za walio na matatizo ya kuona au kusikia imewasha <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Njia ya mkato ya zana za walio na matatizo ya kuona au kusikia imezima <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Tumia njia ya Mkato wa Zana za walio na matatizo ya kuona au kusikia tena ili kuanzisha kipengele kilichopo cha walio na matatizo ya kuona au kusikia"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Chagua kipengele utakachotumia, ukigonga Kitufe cha zana za walio na matatizo ya kuona au kusikia."</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Ili kubadilisha vipengele, gusa na ushikile Kitufe cha zana za walio na matatizo ya kuona au kusikia."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ukuzaji"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 35592a6..b84d68e 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"உங்கள் மொபைல் நிறுவனத்துடன் வைஃபை அழைப்பைப் பதிவுசெய்வதில் சிக்கல்: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s வைஃபை அழைப்பு"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> வைஃபை அழைப்பு"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN அழைப்பு"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN அழைப்பு"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> வைஃபை"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"வைஃபை அழைப்பு | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"ஆஃப்"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"வைஃபைக்கு முன்னுரிமை"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"மொபைல் தரவிற்கு முன்னுரிமை"</string>
@@ -514,8 +518,7 @@
     <string name="permdesc_imagesWrite" msgid="7073662756617474375">"உங்களின் படத் தொகுப்பை மாற்ற ஆப்ஸை அனுமதிக்கும்."</string>
     <string name="permlab_mediaLocation" msgid="8675148183726247864">"மீடியா தொகுப்பிலிருந்து இடங்களை அறிதல்"</string>
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"உங்களின் மீடியா தொகுப்பிலிருந்து இடங்களை அறிந்துகொள்ள ஆப்ஸை அனுமதிக்கும்."</string>
-    <!-- no translation found for biometric_error_hw_unavailable (645781226537551036) -->
-    <skip />
+    <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"பயோமெட்ரிக் வன்பொருள் இல்லை"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"கைரேகையை ஓரளவுதான் கண்டறிய முடிந்தது. மீண்டும் முயலவும்."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"கைரேகையைச் செயலாக்க முடியவில்லை. மீண்டும் முயலவும்."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"கைரேகை உணர்வியில் தூசி உள்ளது. சுத்தம் செய்து, முயலவும்."</string>
@@ -523,9 +526,10 @@
     <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"விரலை மிகவும் மெதுவாக நகர்த்திவிட்டீர்கள். மீண்டும் முயற்சிக்கவும்."</string>
   <string-array name="fingerprint_acquired_vendor">
   </string-array>
-    <!-- no translation found for biometric_not_recognized (5770511773560736082) -->
-    <skip />
+    <string name="biometric_not_recognized" msgid="5770511773560736082">"அடையாளங்காணபடவில்லை"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"கைரேகை அங்கீகரிக்கப்பட்டது"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"முகம் அங்கீகரிக்கப்பட்டது"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"முகம் அங்கீகரிக்கப்பட்டது. ’உறுதிப்படுத்துக’ என்பதை அழுத்துக"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"கைரேகை வன்பொருள் இல்லை."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"கைரேகையைச் சேமிக்க முடியவில்லை. ஏற்கனவே உள்ள கைரேகையை அகற்றவும்."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"கைரேகைக்கான நேரம் முடிந்தது. மீண்டும் முயலவும்."</string>
@@ -562,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"முகப் பதிவிற்கான நேரம் முடிந்தது. மீண்டும் முயல்க."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"முகத்தைச் சேமிக்க இயலாது."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"முக அங்கீகாரச் செயல்பாடு ரத்துசெய்யப்பட்டது."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"பயனர், முக அங்கீகாரத்தை ரத்துசெய்தார்."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"பலமுறை முயன்றுவிட்டீர்கள். பிறகு முயலவும்."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"பலமுறை தோல்வி. முக அங்கீகாரம் முடக்கப்பட்டது."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"மீண்டும் முயலவும்."</string>
@@ -1619,6 +1624,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"வண்ணத் திருத்தம்"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"அணுகல்தன்மைக் குறுக்குவழியானது <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ஐ இயக்கியது"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"அணுகல்தன்மைக் குறுக்குவழியானது <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ஐ முடக்கியது"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"தற்போதுள்ள அணுகல்தன்மை அம்சத்தை மீண்டும் தொடங்க ’அணுகல்தன்மை ஷார்ட்கட்டைப்’ பயன்படுத்தவும்"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"அணுகல்தன்மைப் பொத்தானைத் தட்டி, பயன்படுத்துவதற்கான அம்சத்தைத் தேர்ந்தெடுக்கவும்:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"அம்சங்களை மாற்ற, அணுகல்தன்மைப் பொத்தானைத் தொட்டுப் பிடித்திருக்கவும்."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"பெரிதாக்கல்"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 2027d33..a5430b6 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"మీ క్యారియర్‌తో Wi‑Fi కాలింగ్‌ని నమోదు చేయడంలో సమస్య: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Wi-Fi కాలింగ్"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi కాలింగ్"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN కాల్"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN కాల్"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"WiFi కాలింగ్ | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"ఆఫ్‌లో ఉంది"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fiకి ప్రాధాన్యత"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"మొబైల్‌కి ప్రాధాన్యత ఇవ్వబడింది"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"గుర్తించలేదు"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"వేలిముద్ర ప్రమాణీకరించబడింది"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"ముఖం ప్రమాణీకరించబడింది"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"ముఖం ప్రమాణీకరించబడింది, దయచేసి ధృవీకరించును నొక్కండి"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"వేలిముద్ర హార్డ్‌వేర్ అందుబాటులో లేదు."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"వేలిముద్రను నిల్వ చేయడం సాధ్యపడదు. దయచేసి ఇప్పటికే ఉన్న వేలిముద్రను తీసివేయండి."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"వేలిముద్ర గడువు సమయం చేరుకుంది. మళ్లీ ప్రయత్నించండి."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"ముఖ గడువు సమయం చేరుకుంది. మళ్లీ ప్రయత్నించండి."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"ముఖం నిల్వ చేయబడదు."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"ముఖ కార్యకలాపం రద్దయింది."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"వినియోగదారు ద్వారా ముఖ ప్రమాణీకరణ రద్దు చేయబడింది."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"చాలా ఎక్కువ ప్రయత్నాలు చేసారు. తర్వాత మళ్లీ ప్రయత్నించండి."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"చాలా ఎక్కువ ప్రయత్నాలు చేసారు. ముఖ ప్రమాణీకరణ నిలిపివేయబడింది."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"మళ్లీ ప్రయత్నించండి."</string>
@@ -1617,6 +1624,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"రంగు సవరణ"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"యాక్సెస్ సామర్థ్య షార్ట్‌కట్ ద్వారా <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ఆన్ చేయబడింది"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"యాక్సెస్ సామర్థ్య షార్ట్‌కట్ ద్వారా <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ఆఫ్ చేయబడింది"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"ప్రస్తుత యాక్సెస్ సౌలభ్య ఫీచర్‌ను ఉపయోగించడానికి యాక్సెసిబిలిటీ షార్ట్‌కట్‌ను మళ్లీ ప్రారంభించండి"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"యాక్సెస్ సామర్థ్య బటన్‌ను మీరు నొక్కినప్పుడు ఉపయోగించాల్సిన ఒక ఫీచర్‌ను ఎంచుకోండి:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ఫీచర్లను మార్చడానికి, యాక్సెస్ సామర్థ్య బటన్‌ను నొక్కి &amp; పట్టుకోండి."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"మాగ్నిఫికేషన్"</string>
diff --git a/core/res/res/values-television/themes.xml b/core/res/res/values-television/themes.xml
index 0712cbc..48b59c7 100644
--- a/core/res/res/values-television/themes.xml
+++ b/core/res/res/values-television/themes.xml
@@ -15,7 +15,6 @@
 -->
 <resources>
     <style name="Theme.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
-    <style name="Theme.DeviceDefault.Dialog.AppError" parent="Theme.Leanback.Dialog.AppError" />
     <style name="Theme.Holo.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
     <style name="Theme.Holo.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
     <style name="Theme.Material.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
diff --git a/core/res/res/values-television/themes_device_defaults.xml b/core/res/res/values-television/themes_device_defaults.xml
index 293591a..fdd0624 100644
--- a/core/res/res/values-television/themes_device_defaults.xml
+++ b/core/res/res/values-television/themes_device_defaults.xml
@@ -15,8 +15,20 @@
 -->
 <resources>
     <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
+    <style name="Theme.DeviceDefault.Dialog.AppError" parent="Theme.Leanback.Dialog.AppError" />
     <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
-    <style name="Theme.DeviceDefault.Autofill" parent="Theme.Material.Autofill" />
-    <style name="Theme.DeviceDefault.Autofill.Save" parent="Theme.Material.Autofill.Save" />
+
+    <!-- TODO(b/116457731): remove colorBackground from colors_material.xml if not used anymore -->
+    <style name="Theme.DeviceDefault.Autofill" parent="Theme.Material">
+        <item name="colorBackground">@color/autofill_background_material_dark</item>
+    </style>
+    <style name="Theme.DeviceDefault.Autofill.Save" parent="Theme.Material.Panel">
+        <item name="colorBackground">@color/autofill_background_material_dark</item>
+    </style>
+
+    <!-- TV always use dark mode -->
+    <style name="Theme.DeviceDefault.Autofill.Light" parent="Theme.DeviceDefault.Autofill"/>
+    <style name="Theme.DeviceDefault.Light.Autofill.Save" parent="Theme.DeviceDefault.Autofill.Save"/>
+
     <style name="Theme.DeviceDefault.Resolver" parent="Theme.Leanback.Resolver" />
 </resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 84fd018..0b7e031 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"เกิดปัญหาในการลงทะเบียนการโทรผ่าน Wi‑Fi กับผู้ให้บริการของคุณ: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"กำลังเรียก Wi-Fi ของ %s"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"การโทรผ่าน Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"การโทรผ่าน WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"การโทรผ่าน WLAN <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"การโทรผ่าน Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"ปิด"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"ต้องการใช้ Wi-Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"ต้องการใช้อินเทอร์เน็ตมือถือ"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"ไม่รู้จัก"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"ตรวจสอบสิทธิ์ลายนิ้วมือแล้ว"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"ตรวจสอบสิทธิ์ใบหน้าแล้ว"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"ตรวจสอบสิทธิ์ใบหน้าแล้ว โปรดกดยืนยัน"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ฮาร์ดแวร์ลายนิ้วมือไม่พร้อมใช้งาน"</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"ไม่สามารถเก็บลายนิ้วมือได้ โปรดนำลายนิ้วมือที่มีอยู่ออก"</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"หมดเวลาใช้ลายนิ้วมือแล้ว โปรดลองอีกครั้ง"</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"หมดเวลาใช้ใบหน้าแล้ว โปรดลองอีกครั้ง"</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"จัดเก็บข้อมูลใบหน้าไม่ได้"</string>
     <string name="face_error_canceled" msgid="283945501061931023">"ยกเลิกการดำเนินการกับใบหน้าแล้ว"</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"ผู้ใช้ยกเลิกการตรวจสอบสิทธิ์ใบหน้า"</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"ดำเนินการหลายครั้งเกินไป ลองอีกครั้งในภายหลัง"</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"ดำเนินการหลายครั้งเกินไป ปิดใช้การตรวจสอบสิทธิ์ด้วยใบหน้าแล้ว"</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"ลองอีกครั้ง"</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"การปรับแก้สี"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ทางลัดการเข้าถึงเปิด <xliff:g id="SERVICE_NAME">%1$s</xliff:g> แล้ว"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ทางลัดการเข้าถึงปิด <xliff:g id="SERVICE_NAME">%1$s</xliff:g> แล้ว"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"ใช้ทางลัดการช่วยเหลือพิเศษอีกครั้งเพื่อเริ่มฟีเจอร์การช่วยเหลือพิเศษปัจจุบัน"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"เลือกฟีเจอร์ที่จะใช้เมื่อคุณแตะปุ่ม \"การเข้าถึงพิเศษ\":"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"หากต้องการเปลี่ยนฟีเจอร์ ให้แตะปุ่ม \"การเข้าถึงพิเศษ\" ค้างไว้"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"การขยาย"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 49318cf..e21f59c 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Nagkaroon ng isyu sa pagrehistro ng pagtawag gamit ang Wi‑Fi sa iyong carrier: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"Pagtawag sa Pamamagitan ng Wi-Fi ng %s"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Pagtawag Gamit ang Wi-Fi ng <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Pagtawag Gamit ang WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Pagtawag Gamit ang WLAN ng <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi ng <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Pagtawag Gamit ang Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi ng <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Naka-off"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Mas gusto ang Wi-Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Mas gusto ang mobile"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Hindi nakilala"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Na-authenticate ang fingerprint"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Na-authenticate ang mukha"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Na-authenticate ang mukha, pakipindot ang kumpirmahin"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hindi available ang hardware na ginagamitan ng fingerprint."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Hindi maiimbak ang fingerprint. Mangyaring mag-alis ng umiiral nang fingerprint."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Nag-time out ang fingerprint. Subukang muli."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Nag-time out ang mukha. Subukang muli."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Hindi ma-store ang mukha."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Nakansela ang operation kaugnay ng mukha."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Kinansela ng user ang pag-authenticate ng mukha."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Masyadong maraming pagsubok. Subukang muli mamaya."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Sobrang pagsubok. Bawal na: facial authentication."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Subukang muli."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Pagwawasto ng Kulay"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Na-on ng Shortcut sa Accessibility ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Na-off ng Shortcut sa Accessibility ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Gamiting muli ang Shortcut sa Pagiging Naa-access para simulan ang kasalukuyang feature ng pagiging naa-access"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Pumili ng feature na gagamitin kapag na-tap mo ang button ng Pagiging Naa-access:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Upang baguhin ang mga feature, pindutin nang matagal ang button ng Pagiging Naa-access."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Pag-magnify"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index c6d18ec..41616df 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Kablosuz çağrının operatörünüze kaydı sırasında hata oluştu: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Kablosuz Çağrı"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Kablosuz Çağrı"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN Üzerinden Çağrı"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN Üzerinden Çağrı"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Kablosuz"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Kablosuz Çağrı | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Kapalı"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Kablosuz bağlantı tercihli"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Mobil tercihli"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Tanınmadı"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Parmak izi kimlik doğrulaması yapıldı"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Yüz kimliği doğrulandı"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Yüz kimliği doğrulandı, lütfen doğrula\'ya basın"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Parmak izi donanımı kullanılamıyor."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Parmak izi depolanamıyor. Lütfen mevcut parmak izlerinden birini kaldırın."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Parmak izi için zaman aşımı oluştu. Tekrar deneyin."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Yüz için zaman aşımı oluştu. Tekrar deneyin."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Yüz kaydedilemiyor."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Yüz işlemi iptal edildi."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Yüz kimlik doğrulama işlemini kullanıcı iptal etti."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Çok fazla deneme yapıldı. Daha sonra tekrar deneyin."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Çok fazla deneme yapıldı. Yüz kimlik doğrulaması devre dışı bırakıldı."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Tekrar deneyin."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Renk Düzeltme"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Erişilebilirlik Kısayolu <xliff:g id="SERVICE_NAME">%1$s</xliff:g> hizmetini açtı"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Erişilebilirlik Kısayolu <xliff:g id="SERVICE_NAME">%1$s</xliff:g> hizmetini kapattı"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Geçerli erişilebilirlik özelliğini başlatmak için Erişilebilirlik Kısayolu\'nu tekrar kullanın"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Erişilebilirlik düğmesine dokunduğunuzda kullanmak üzere bir özellik seçin:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Özellikleri değiştirmek için Erişilebilirlik düğmesine dokunup basılı tutun."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Büyütme"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 6e6dd9a..f84e3e2 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -130,10 +130,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Проблема з реєстрацією дзвінків через Wi‑Fi у вашого оператора: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"Дзвінок через Wi-Fi від оператора %s"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Виклики <xliff:g id="SPN">%s</xliff:g> через Wi-Fi"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Виклик через WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Виклик <xliff:g id="SPN">%s</xliff:g> через WLAN"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> через Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Виклики через Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> через VoWi-Fi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Вимкнено"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi за умовчанням"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Мобільна мережа за умовчанням"</string>
@@ -530,6 +534,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Не розпізнано"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Відбиток автентифіковано"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Обличчя автентифіковано"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Обличчя автентифіковано. Натисніть \"Підтвердити\""</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Апаратне забезпечення для сканування відбитка недоступне."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Не вдалося зберегти відбиток. Видаліть наявний відбиток."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Час очікування відбитка минув. Повторіть спробу."</string>
@@ -566,6 +572,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Час очікування обличчя минув. Повторіть спробу."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Не вдається зберегти обличчя."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Дію з обличчям скасовано."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Користувач скасував автентифікацію облич."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Забагато спроб. Повторіть пізніше."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Забагато спроб. Автентифікацію обличчя вимкнено."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Повторіть спробу."</string>
@@ -1664,6 +1671,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Корекція кольорів"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Ярлик спеціальних можливостей увімкнув <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Ярлик спеціальних можливостей вимкнув <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Щоб запустити поточну функцію спеціальних можливостей, знову скористайтеся відповідним ярликом"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Виберіть функцію для кнопки спеціальних можливостей:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Щоб змінити функцію, натисніть і втримуйте кнопку спеціальних можливостей."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Збільшення"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 2a2ca62..dc801cd 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"‏آپ کے کیریئر کے ساتھ Wi‑Fi کالنگ رجسٹر کرنے میں مسئلہ درپیش ہے: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"‎%s"</item>
-    <item msgid="4397097370387921767">"‏‎%s Wi-Fi کالنگ"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"‏<xliff:g id="SPN">%s</xliff:g> Wi-Fi کالنگ"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"‏WLAN کال"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"‏<xliff:g id="SPN">%s</xliff:g> WLAN کال"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"‏WiFi کالنگ | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"آف"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"‏Wi-Fi ترجیحی"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"موبائل ترجیحی"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"تسلیم شدہ نہیں ہے"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"فنگر پرنٹ کی تصدیق ہو گئی"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"چہرے کی تصدیق ہو گئی"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"چہرے کی تصدیق ہو گئی، براہ کرم \'تصدیق کریں\' کو دبائيں"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"فنگر پرنٹ ہارڈ ویئر دستیاب نہیں ہے۔"</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"فنگر پرنٹ اسٹور نہیں کیا جا سکتا ہے۔ براہ کرم ایک موجودہ فنگر پرنٹ ہٹائیں۔"</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"فنگر پرنٹ کی میعاد ختم ہوگئی۔ دوبارہ کوشش کریں۔"</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"چہرہ پہچانے کی میعاد ختم ہو گئی۔ دوبارہ کوشش کریں۔"</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"چہرے کو اسٹور نہیں کیا جا سکتا۔"</string>
     <string name="face_error_canceled" msgid="283945501061931023">"چہرے پر ہونے والی کارروائی منسوخ ہو گئی۔"</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"صارف نے چہرے کی تصدیق کو مسترد کر دیا۔"</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"کافی زیادہ کوششیں کی گئیں۔ دوبارہ کوشش کریں۔"</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"کافی زیادہ کوششیں کی گئیں۔ چہرے کی توثیق منسوخ ہو گئی۔"</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"دوبارہ کوشش کریں۔"</string>
@@ -1617,6 +1624,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"رنگ کی تصحیح"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ایکسیسبیلٹی شارٹ کٹ نے <xliff:g id="SERVICE_NAME">%1$s</xliff:g> کو آن کر دیا"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ایکسیسبیلٹی شارٹ کٹ نے <xliff:g id="SERVICE_NAME">%1$s</xliff:g> کو آف کر دیا"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"موجودہ ایکسیسبیلٹی خصوصیت کو شروع کرنے کیلئے دوبارہ ایکسیسبیلٹی شارٹ کٹ استعمال کریں"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ایکسیسبیلٹی بٹن پر تھپتھپانے وقت استعمال کرنے کیلئے ایک خصوصیت چنیں:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"خصوصیات تبدیل کرنے کیلئے، ایکسیسبیلٹی بٹن ٹچ کریں اور دبائے رکھیں۔"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"میگنیفکیشن"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 7ffc7e7..e51b810 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Aloqa operatoringiz orqali Wi-Fi chaqiruv funksiyasinini ulashda xato: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Wi-Fi qo‘ng‘iroqlar"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi chaqiruv"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN chaqiruv"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN chaqiruv"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi chaqiruv | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWi-Fi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"O‘chiq"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi afzalligi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Mobil internet afzalligi"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Aniqlanmadi"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Barmoq izi tekshirildi"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Yuzingiz aniqlandi"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Yuzingiz aniqlandi, tasdiqlash uchun bosing"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Barmoq izi skaneri ish holatida emas."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Barmoq izini saqlab bo‘lmadi. Mavjud barmoq izlaridan birini o‘chirib tashlang."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Barmoq izini aniqlash vaqti tugab qoldi. Qayta urinib ko‘ring."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Yuzni aniqlash vaqti tugadi. Qaytadan urining."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Aniqlangan yuz saqlanmadi."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Yuzni aniqlash bekor qilindi."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Yuz tekshiruvi bekor qilindi."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Juda ko‘p urinildi. Keyinroq qaytadan urining."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Juda ko‘p urinildi. Skaner faolsizlantirildi."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Qaytadan urining."</string>
@@ -1617,6 +1624,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Rangni tuzatish"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> xizmati yoqildi"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> xizmati o‘chirib qo‘yildi"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Joriy maxsus imkoniyatlar funksiyasini boshlash uchun tezkor ishga tushirishdan qayta foydalaning"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Maxsus imkoniyatlar tugmasi bosilganda ishga tushadigan funksiyani tanlang:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Funksiyalarni o‘zgartirish uchun Maxsus imkoniyatlar tugmasini bosib turing."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Kattalashtirish"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index a5f458b..4d8a20b 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Sự cố khi đăng ký dịch vụ gọi qua Wi‑Fi với nhà mạng của bạn: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"Gọi điện qua Wi-Fi %s"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Gọi qua Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Cuộc gọi qua WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Cuộc gọi qua WLAN <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Gọi qua Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Tắt"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Ưu tiên Wi-Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Ưu tiên dữ liệu di động"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Không nhận dạng được"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Đã xác thực vân tay"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Đã xác thực khuôn mặt"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Đã xác thực khuôn mặt, vui lòng nhấn để xác nhận"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Phần cứng vân tay không khả dụng."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Không thể lưu vân tay. Vui lòng xóa vân tay hiện có."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Đã hết thời gian chờ vân tay. Hãy thử lại."</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Đã hết thời gian chờ khuôn mặt. Hãy thử lại."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Không thể lưu khuôn mặt."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Đã hủy thao tác dùng khuôn mặt."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Người dùng đã hủy thao tác xác thực khuôn mặt."</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Bạn đã thử quá nhiều lần. Hãy thử lại sau."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Đã thử quá nhiều lần. Đã tắt xác thực khuôn mặt."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Hãy thử lại."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Sửa màu"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Đã bật phím tắt trợ năng <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Đã tắt phím tắt trợ năng <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Sử dụng lại Phím tắt hỗ trợ tiếp cận để bắt đầu tính năng hỗ trợ tiếp cận hiện tại"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Chọn tính năng sẽ sử dụng khi bạn nhấn nút Trợ năng:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Để thay đổi các tính năng, hãy chạm và giữ nút Trợ năng."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Phóng to"</string>
diff --git a/core/res/res/values-watch/themes.xml b/core/res/res/values-watch/themes.xml
deleted file mode 100644
index 1be47ba..0000000
--- a/core/res/res/values-watch/themes.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<resources>
-    <!-- Theme for the dialog shown when an app crashes or ANRs. Override to make it dark. -->
-    <style name="Theme.DeviceDefault.Dialog.AppError" parent="Theme.DeviceDefault.Dialog.Alert">
-        <item name="windowContentTransitions">false</item>
-        <item name="windowActivityTransitions">false</item>
-        <item name="windowCloseOnTouchOutside">false</item>
-    </style>
-</resources>
diff --git a/core/res/res/values-watch/themes_device_defaults.xml b/core/res/res/values-watch/themes_device_defaults.xml
index a7736e7c..bfba312 100644
--- a/core/res/res/values-watch/themes_device_defaults.xml
+++ b/core/res/res/values-watch/themes_device_defaults.xml
@@ -422,6 +422,13 @@
         <item name="secondaryContentAlpha">@dimen/secondary_content_alpha_device_default</item>
     </style>
 
+    <!-- Theme for the dialog shown when an app crashes or ANRs. Override to make it dark. -->
+    <style name="Theme.DeviceDefault.Dialog.AppError" parent="Theme.DeviceDefault.Dialog.Alert">
+        <item name="windowContentTransitions">false</item>
+        <item name="windowActivityTransitions">false</item>
+        <item name="windowCloseOnTouchOutside">false</item>
+    </style>
+
     <style name="Theme.DeviceDefault.SearchBar" parent="Theme.Material.SearchBar">
         <!-- Color palette Dark -->
         <item name="colorPrimary">@color/primary_device_default_dark</item>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 966a5a5..609f9bcf 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"向您的运营商注册 WLAN 通话时遇到问题:<xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s WLAN 通话功能"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> WLAN 通话"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN 通话"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN 通话"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> WLAN"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"WLAN 通话 | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"关闭"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"首选 WLAN"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"首选移动数据网络"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"无法识别"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"已验证指纹"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"面孔已验证"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"面孔已验证,请按确认按钮"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"指纹硬件无法使用。"</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"无法存储指纹。请移除一个现有的指纹。"</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"指纹录入操作超时,请重试。"</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"面孔处理操作超时,请重试。"</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"无法存储面孔。"</string>
     <string name="face_error_canceled" msgid="283945501061931023">"面孔处理操作已取消。"</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"用户已取消面孔验证。"</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"尝试次数过多,请稍后重试。"</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"尝试次数过多,系统已停用人脸身份验证功能。"</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"请重试。"</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"色彩校正"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"无障碍快捷方式已开启<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"无障碍快捷方式已关闭<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"再次使用无障碍快捷方式即可启动目前设置的无障碍功能"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"选择按下“无障碍”按钮时要使用的功能:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"要更改指定的功能,请触摸并按住“无障碍”按钮。"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"放大功能"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 87eb41f..2e3c7d7 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"向您的流動網絡供應商註冊 Wi-Fi 通話時發生問題:<xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Wi-Fi 通話"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi 通話"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN 通話"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN 通話"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"WiFi 通話 | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"關閉"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"首選 Wi-Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"流動數據優先"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"未能識別"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"驗證咗指紋"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"面孔已經驗證"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"面孔已經驗證,請㩒一下 [確認]"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"無法使用指紋軟件。"</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"指紋無法儲存。請移除現有指紋。"</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"指紋已逾時。請再試一次。"</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"臉孔操作已逾時,請再試一次。"</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"無法儲存臉孔。"</string>
     <string name="face_error_canceled" msgid="283945501061931023">"臉孔操作已取消。"</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"使用者已取消臉孔驗證。"</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"嘗試次數過多,請稍後再試。"</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"嘗試次數過多,臉孔驗證已停用。"</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"請再試一次。"</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"色彩校正"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"無障礙功能快速鍵已啟用 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"無障礙功能快速鍵已停用 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"再用一次無障礙功能捷徑,就可以啟用宜家設定咗嘅無障礙功能"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"請選擇輕按「無障礙功能」按鈕時使用的功能:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"如要變更功能,可按住「無障礙功能」按鈕。"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"放大"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index bd36ed6..9149f47 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"向你的電信業者註冊 Wi‑Fi 通話時發生問題:<xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s Wi-Fi 通話"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi 通話"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN 通話"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN 通話"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi 通話 | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"關閉"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi 優先"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"行動網路優先"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"無法辨識"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"指紋驗證成功"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"臉孔驗證成功"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"臉孔驗證成功,請按下 [確認] 按鈕"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"指紋硬體無法使用。"</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"無法儲存指紋,請先移除現有指紋。"</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"指紋處理作業逾時,請再試一次。"</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"臉孔處理作業逾時,請再試一次。"</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"無法儲存臉孔。"</string>
     <string name="face_error_canceled" msgid="283945501061931023">"臉孔處理作業已取消。"</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"使用者已取消臉孔驗證。"</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"嘗試次數過多,請稍後再試。"</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"嘗試次數過多,臉孔驗證功能已停用。"</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"請再試一次。"</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"色彩校正"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"協助工具捷徑啟用了「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"協助工具捷徑停用了「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"再次使用協助工具捷徑即可啟動目前設定的無障礙功能"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"輕觸 [協助工具] 按鈕後,選擇你想使用的功能:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"如要變更指派的功能,請按住 [協助工具] 按鈕。"</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"放大"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index fd6614c..75709ca 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -128,10 +128,14 @@
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="7372514042696663278">"Inkinga yokubhalisa ukushaya kwe-Wi-Fi ngenkampani yakho yenethiwekhi: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"%s ukushaya kwe-Wi-Fi"</item>
-  </string-array>
+    <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+    <skip />
+    <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> ukushaya kwe-Wi-Fi"</string>
+    <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Ikholi ye-WLAN"</string>
+    <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> ikholi ye-WLAN"</string>
+    <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+    <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Ukushaya kwe-WiFi | <xliff:g id="SPN">%s</xliff:g>"</string>
+    <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Valiwe"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Kuncanyelwa i-Wi-Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Kuncanyelwa iselula"</string>
@@ -524,6 +528,8 @@
   </string-array>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Akwaziwa"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"Isingxivizo somunwe sigunyaziwe"</string>
+    <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Ubuso bufakazelwe ubuqiniso"</string>
+    <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Ukuqinisekiswa kobuso, sicela ucindezele okuthi qinisekisa"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Izingxenyekazi zekhompuyutha zezingxivizo zeminwe azitholakali."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Izigxivizo zeminwe azikwazi ukugcinwa. Sicela ususe izigxivizo zeminwe ezikhona."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Kufinyelelwe isikhathi sokuvala sezigxivizo zeminwe. Zama futhi"</string>
@@ -560,6 +566,7 @@
     <string name="face_error_timeout" msgid="4014326147867150054">"Kufinyelelwe kusikhathi sokuvala sobuso. Zama futhi."</string>
     <string name="face_error_no_space" msgid="8224993703466381314">"Ubuso abukwazi ukugcinwa."</string>
     <string name="face_error_canceled" msgid="283945501061931023">"Umsebenzi wobuso ukhanselwe."</string>
+    <string name="face_error_user_canceled" msgid="8943921120862164539">"Ukufakazela ubuqiniso kobuso kukhanselwe umsebenzisi"</string>
     <string name="face_error_lockout" msgid="3407426963155388504">"Imizamo eminingi kakhulu. Zama futhi emuva kwesikhathi."</string>
     <string name="face_error_lockout_permanent" msgid="8198354656746088890">"Imizamo eminingi kakhulu. Ukufakazela ubuqiniso kobuso kukhutshaziwe."</string>
     <string name="face_error_unable_to_process" msgid="238761109287767270">"Zama futhi."</string>
@@ -1616,6 +1623,7 @@
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Ukulungiswa kombala"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Isinqamuleli sokufinyelela sivule i-<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Isinqamuleli sokufinyelela sivale i-<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Sebenzisa isinqamuleli sokufinyelela futhi ukuze uqale isici samanje sokufinyelela"</string>
     <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Khetha isici ozosisebenzisa uma uthepha inkinobho yokufinyelela:"</string>
     <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Ukuze ushintshe izici, thinta uphinde ubambe inkinobho yokufinyelela."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ukukhuliswa"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 2de2b9e..65b8807 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3606,6 +3606,8 @@
             <flag name="flagRequestAccessibilityButton" value="0x00000100" />
             <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_FINGERPRINT_GESTURES}. -->
             <flag name="flagRequestFingerprintGestures" value="0x00000200" />
+            <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK}. -->
+            <flag name="flagRequestShortcutWarningDialogSpokenFeedback" value="0x00000400" />
         </attr>
         <!-- Component name of an activity that allows the user to modify
              the settings for this service. This setting cannot be changed at runtime. -->
diff --git a/core/res/res/values/colors_car.xml b/core/res/res/values/colors_car.xml
index 6053728..32671ac8 100644
--- a/core/res/res/values/colors_car.xml
+++ b/core/res/res/values/colors_car.xml
@@ -17,15 +17,271 @@
  */
 -->
 <resources>
-  <!-- car support colors from
-  https://cs.corp.google.com/android/frameworks/support/car/res/values/colors.xml -->
-  <color name="car_user_switcher_user_image_bgcolor">@color/car_grey_50</color>
-  <color name="car_user_switcher_user_image_fgcolor">@color/car_grey_900</color>
-  <color name="car_card_dark">@color/car_dark_blue_grey_700</color>
-  <color name="car_body1_light">@color/car_grey_100</color>
+    <color name="car_background">@color/black</color>
 
-  <color name="car_grey_50">#fffafafa</color>
-  <color name="car_grey_900">#ff212121</color>
-  <color name="car_dark_blue_grey_700">#ff172026</color>
-  <color name="car_grey_100">#fff5f5f5</color>
+    <color name="car_colorPrimary">@color/car_grey_868</color>
+    <color name="car_colorSecondary">@color/car_grey_900</color>
+    <color name="car_colorPrimaryDark">@color/car_grey_958</color>
+
+
+    <!-- Various colors for text sizes. "Light" and "dark" here refer to the lighter or darker
+          shades. -->
+    <color name="car_title_light">@color/car_grey_100</color>
+    <color name="car_title_dark">@color/car_grey_900</color>
+    <color name="car_title">@color/car_title_light</color>
+
+    <color name="car_title2_light">@color/car_grey_100</color>
+    <color name="car_title2_dark">@color/car_grey_900</color>
+    <color name="car_title2">@color/car_title2_light</color>
+
+    <color name="car_headline1_light">@color/car_grey_100</color>
+    <color name="car_headline1_dark">@color/car_grey_800</color>
+    <color name="car_headline1">@color/car_headline1_light</color>
+
+    <color name="car_headline2_light">@color/car_grey_100</color>
+    <color name="car_headline2_dark">@color/car_grey_900</color>
+    <color name="car_headline2">@color/car_headline2_light</color>
+
+    <color name="car_headline3_light">@android:color/white</color>
+    <color name="car_headline3_dark">@color/car_grey_900</color>
+    <color name="car_headline3">@color/car_headline3_light</color>
+
+    <color name="car_headline4_light">@android:color/white</color>
+    <color name="car_headline4_dark">@android:color/black</color>
+    <color name="car_headline4">@color/car_headline4_light</color>
+
+    <color name="car_body1_light">@color/car_grey_100</color>
+    <color name="car_body1_dark">@color/car_grey_900</color>
+    <color name="car_body1">@color/car_body1_light</color>
+
+    <color name="car_body2_light">@color/car_grey_300</color>
+    <color name="car_body2_dark">@color/car_grey_700</color>
+    <color name="car_body2">@color/car_body2_light</color>
+
+    <color name="car_body3_light">@android:color/white</color>
+    <color name="car_body3_dark">@android:color/black</color>
+    <color name="car_body3">@color/car_body3_light</color>
+
+    <color name="car_body4_light">@android:color/white</color>
+    <color name="car_body4_dark">@android:color/black</color>
+    <color name="car_body4">@color/car_body4_light</color>
+
+    <color name="car_action1_light">@color/car_grey_900</color>
+    <color name="car_action1_dark">@color/car_grey_50</color>
+    <color name="car_action1">@color/car_action1_light</color>
+
+    <!-- The tinting colors to create a light- and dark-colored icon respectively. -->
+    <color name="car_tint_light">@color/car_grey_50</color>
+    <color name="car_tint_dark">@color/car_grey_900</color>
+
+    <!-- The tinting color for an icon. This icon is assumed to be on a light background. -->
+    <color name="car_tint">@color/car_tint_light</color>
+
+    <!-- An inverted tinting from car_tint. -->
+    <color name="car_tint_inverse">@color/car_tint_dark</color>
+
+    <!-- The color of the divider. The color here is a lighter shade. -->
+    <color name="car_list_divider_light">#1fffffff</color>
+
+    <!-- The color of the divider. The color here is a darker shade. -->
+    <color name="car_list_divider_dark">#1f000000</color>
+
+    <!-- The color of the dividers in the list. This color is assumed to be on a light colored
+         view. -->
+    <color name="car_list_divider">@color/car_list_divider_light</color>
+
+    <!-- A light and dark colored card. -->
+    <color name="car_card_light">@color/car_grey_50</color>
+    <color name="car_card_dark">@color/car_dark_blue_grey_700</color>
+
+    <!-- The default color of a card in car UI. -->
+    <color name="car_card">@color/car_card_dark</color>
+
+    <!-- The ripple colors. The "dark" and "light" designation here refers to the color of the
+         ripple  itself. -->
+    <color name="car_card_ripple_background_dark">#8F000000</color>
+    <color name="car_card_ripple_background_light">#27ffffff</color>
+
+    <!-- The ripple color for a light colored card. -->
+    <color name="car_card_ripple_background">@color/car_card_ripple_background_light</color>
+
+    <!-- The ripple color for a dark-colored card. This color is the opposite of
+         car_card_ripple_background. -->
+    <color name="car_card_ripple_background_inverse">@color/car_card_ripple_background_dark</color>
+
+    <!-- The top margin before the start of content in an application. -->
+    <dimen name="app_header_height">96dp</dimen>
+
+    <!-- The lighter and darker color for the scrollbar thumb. -->
+    <color name="car_scrollbar_thumb_light">#99ffffff</color>
+    <color name="car_scrollbar_thumb_dark">#7f0b0f12</color>
+
+    <!-- The color of the scroll bar indicator in the PagedListView. This color is assumed to be on
+         a light-colored background. -->
+    <color name="car_scrollbar_thumb">@color/car_scrollbar_thumb_light</color>
+
+    <!-- The inverted color of the scroll bar indicator. This color is always the opposite of
+         car_scrollbar_thumb. -->
+    <color name="car_scrollbar_thumb_inverse">@color/car_scrollbar_thumb_dark</color>
+
+    <!-- The color of the seekbar track secondary progress in SeekbarListItem. -->
+    <color name="car_seekbar_track_secondary_progress">@color/car_grey_500</color>
+
+    <!-- The lighter and darker color for the seekbar track background. -->
+    <color name="car_seekbar_track_background_light">@color/car_grey_400</color>
+    <color name="car_seekbar_track_background_dark">@color/car_grey_700</color>
+    <!-- The color of the seekbar track background in SeekbarListItem. This color is assumed to be
+         on a light-colored background. -->
+    <color name="car_seekbar_track_background">@color/car_seekbar_track_background_dark</color>
+    <!-- background is car_grey_868 with .9 alpha -->
+    <color name="car_toast_background">#E6282a2d</color>
+
+    <!-- Misc colors -->
+    <color name="car_highlight_light">@color/car_teal_700</color>
+    <color name="car_highlight_dark">@color/car_teal_200</color>
+    <color name="car_highlight">@color/car_highlight_dark</color>
+    <color name="car_accent_light">@color/car_highlight_light</color>
+    <color name="car_accent_dark">@color/car_highlight_dark</color>
+    <color name="car_accent">@color/car_highlight_dark</color>
+
+    <color name="car_user_switcher_user_image_bgcolor">@color/car_grey_50</color>
+    <color name="car_user_switcher_user_image_fgcolor">@color/car_grey_900</color>
+
+    <!-- Color palette for cars -->
+    <color name="car_grey_958">#ff0e1013</color>
+    <color name="car_grey_928">#ff17181b</color>
+    <color name="car_grey_900">#ff202124</color>
+    <color name="car_grey_868">#ff282a2d</color>
+    <color name="car_grey_846">#ff2e3234</color>
+    <color name="car_grey_800">#ff3c4043</color>
+    <color name="car_grey_772">#ff464a4d</color>
+    <color name="car_grey_746">#ff4d5256</color>
+    <color name="car_grey_700">#ff5f6368</color>
+    <color name="car_grey_600">#ff80868b</color>
+    <color name="car_grey_500">#ff9aa0a6</color>
+    <color name="car_grey_400">#ffbdc1c6</color>
+    <color name="car_grey_300">#ffdadce0</color>
+    <color name="car_grey_200">#ffe8eaed</color>
+    <color name="car_grey_100">#fff1f3f4</color>
+    <color name="car_grey_50">#fff8f9fa</color>
+
+    <color name="car_blue_900">#ff1d57a9</color>
+    <color name="car_blue_800">#ff2065bb</color>
+    <color name="car_blue_700">#ff2374ce</color>
+    <color name="car_blue_600">#ff2581df</color>
+    <color name="car_blue_500">#ff5195ea</color>
+    <color name="car_blue_400">#ff6ba5ed</color>
+    <color name="car_blue_300">#ff96bff2</color>
+    <color name="car_blue_200">#ffb9d4f6</color>
+    <color name="car_blue_100">#ffd9e6f9</color>
+    <color name="car_blue_50">#ffebf1fc</color>
+
+    <color name="car_green_900">#ff136e39</color>
+    <color name="car_green_800">#ff1b7e42</color>
+    <color name="car_green_700">#ff218c48</color>
+    <color name="car_green_600">#ff28994f</color>
+    <color name="car_green_500">#ff41af6a</color>
+    <color name="car_green_400">#ff5dba80</color>
+    <color name="car_green_300">#ff8dcfa5</color>
+    <color name="car_green_200">#ffb3dfc3</color>
+    <color name="car_green_100">#ffd5ebdf</color>
+    <color name="car_green_50">#ffe8f3ee</color>
+
+    <color name="car_red_900">#ffa81314</color>
+    <color name="car_red_800">#ffb41b1a</color>
+    <color name="car_red_700">#ffc22a2a</color>
+    <color name="car_red_600">#ffd33b30</color>
+    <color name="car_red_500">#ffe25142</color>
+    <color name="car_red_400">#ffe66a5e</color>
+    <color name="car_red_300">#ffed968d</color>
+    <color name="car_red_200">#fff3b9b3</color>
+    <color name="car_red_100">#fff7d8d9</color>
+    <color name="car_red_50">#fffaebeb</color>
+
+    <color name="car_yellow_900">#ffdd860e</color>
+    <color name="car_yellow_800">#ffe59810</color>
+    <color name="car_yellow_700">#ffeda912</color>
+    <color name="car_yellow_600">#fff3b713</color>
+    <color name="car_yellow_500">#fff5c518</color>
+    <color name="car_yellow_400">#fff6cd3a</color>
+    <color name="car_yellow_300">#fff9dc74</color>
+    <color name="car_yellow_200">#fffbe7a2</color>
+    <color name="car_yellow_100">#fffcf0ce</color>
+    <color name="car_yellow_50">#fffdf7e6</color>
+
+    <color name="car_orange_900">#ffb06000</color>
+    <color name="car_orange_800">#ffc26401</color>
+    <color name="car_orange_700">#ffd56e0c</color>
+    <color name="car_orange_600">#ffe8710a</color>
+    <color name="car_orange_500">#fffa7b17</color>
+    <color name="car_orange_400">#fffa903e</color>
+    <color name="car_orange_300">#fffcad70</color>
+    <color name="car_orange_200">#fffdc69c</color>
+    <color name="car_orange_100">#fffedfc8</color>
+    <color name="car_orange_50">#fffeefe3</color>
+
+    <color name="car_pink_900">#ff9c166b</color>
+    <color name="car_pink_800">#ffb80672</color>
+    <color name="car_pink_700">#ffd01884</color>
+    <color name="car_pink_600">#ffe52592</color>
+    <color name="car_pink_500">#fff439a0</color>
+    <color name="car_pink_400">#ffff63b8</color>
+    <color name="car_pink_300">#ffff8bcb</color>
+    <color name="car_pink_200">#fffba9d6</color>
+    <color name="car_pink_100">#fffdcfe8</color>
+    <color name="car_pink_50">#fffde7f3</color>
+
+    <color name="car_teal_900">#ff004d40</color>
+    <color name="car_teal_800">#ff00695c</color>
+    <color name="car_teal_700">#ff00796b</color>
+    <color name="car_teal_600">#ff00897b</color>
+    <color name="car_teal_500">#ff009688</color>
+    <color name="car_teal_400">#ff26a69a</color>
+    <color name="car_teal_300">#ff4db6ac</color>
+    <color name="car_teal_200">#ff80cbc4</color>
+    <color name="car_teal_100">#ffb2dfdb</color>
+    <color name="car_teal_50">#ffe0f2f1</color>
+
+    <color name="car_purple_900">#ff681da8</color>
+    <color name="car_purple_800">#ff7627bb</color>
+    <color name="car_purple_700">#ff8430ce</color>
+    <color name="car_purple_600">#ff9334e6</color>
+    <color name="car_purple_500">#ffa142f4</color>
+    <color name="car_purple_400">#ffaf5cf7</color>
+    <color name="car_purple_300">#ffc58af9</color>
+    <color name="car_purple_200">#ffd7aefb</color>
+    <color name="car_purple_100">#ffe9d2fd</color>
+    <color name="car_purple_50">#fff3e8fd</color>
+
+    <color name="car_cyan_900">#ff01877e</color>
+    <color name="car_cyan_800">#ff099091</color>
+    <color name="car_cyan_700">#ff12a4af</color>
+    <color name="car_cyan_600">#ff12b5cb</color>
+    <color name="car_cyan_500">#ff24c1e0</color>
+    <color name="car_cyan_400">#ff4ecde6</color>
+    <color name="car_cyan_300">#ff78d9ec</color>
+    <color name="car_cyan_200">#ffa1e4f2</color>
+    <color name="car_cyan_100">#ffcbf0f8</color>
+    <color name="car_cyan_50">#ffe4f7fb</color>
+
+
+    <color name="car_grey_1000">#cc000000</color>
+    <color name="car_white_1000">#1effffff</color>
+    <color name="car_blue_grey_800">#ff37474F</color>
+    <color name="car_blue_grey_900">#ff263238</color>
+    <color name="car_dark_blue_grey_600">#ff1d272d</color>
+    <color name="car_dark_blue_grey_700">#ff172026</color>
+    <color name="car_dark_blue_grey_800">#ff11181d</color>
+    <color name="car_dark_blue_grey_900">#ff0c1013</color>
+    <color name="car_dark_blue_grey_1000">#ff090c0f</color>
+    <color name="car_light_blue_300">#ff4fc3f7</color>
+    <color name="car_light_blue_500">#ff03A9F4</color>
+    <color name="car_light_blue_600">#ff039be5</color>
+    <color name="car_light_blue_700">#ff0288d1</color>
+    <color name="car_light_blue_800">#ff0277bd</color>
+    <color name="car_light_blue_900">#ff01579b</color>
+
+
+    <color name="car_red_500a">#ffd50000</color>
+    <color name="car_red_a700">#ffd50000</color>
 </resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 293d90e..9aebf6c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -913,7 +913,7 @@
     <!--  Control whether to lock day/night mode change from normal application. When it is
           true, day / night mode change is only allowed to apps with MODIFY_DAY_NIGHT_MODE
           permission. -->
-    <bool name="config_lockDayNightMode">true</bool>
+    <bool name="config_lockDayNightMode">false</bool>
 
     <!-- Control the default night mode to use when there is no other mode override set.
          One of the following values (see UiModeManager.java):
@@ -3486,6 +3486,9 @@
     <!-- Name of the font family used for system surfaces where the font should use medium weight -->
     <string name="config_headlineFontFamilyMedium">@string/font_family_button_material</string>
 
+    <!-- Size of icon shown beside a preference locked by admin -->
+    <dimen name="config_restricted_icon_size">@dimen/restricted_icon_size_material</dimen>
+
     <string translatable="false" name="config_batterySaverDeviceSpecificConfig"></string>
 
     <!-- Package name that should be granted Notification Assistant access -->
@@ -3538,4 +3541,13 @@
 
     <!-- Brand value for attestation of misprovisioned device. -->
     <string name="config_misprovisionedBrandValue" translatable="false"></string>
+
+    <!-- Pre-scale volume at volume step 1 for Absolute Volume -->
+    <fraction name="config_prescaleAbsoluteVolume_index1">50%</fraction>
+
+    <!-- Pre-scale volume at volume step 2 for Absolute Volume -->
+    <fraction name="config_prescaleAbsoluteVolume_index2">70%</fraction>
+
+    <!-- Pre-scale volume at volume step 3 for Absolute Volume -->
+    <fraction name="config_prescaleAbsoluteVolume_index3">85%</fraction>
 </resources>
diff --git a/core/res/res/values/dimens_car.xml b/core/res/res/values/dimens_car.xml
index 7d14f86..a0c02ed 100644
--- a/core/res/res/values/dimens_car.xml
+++ b/core/res/res/values/dimens_car.xml
@@ -16,12 +16,86 @@
 */
 -->
 <resources>
-    <!-- TODO replace with car support lib sizes when available -->
     <dimen name="car_fullscreen_user_pod_icon_text_size">64sp</dimen>
     <dimen name="car_fullscreen_user_pod_width">243dp</dimen>
     <dimen name="car_fullscreen_user_pod_height">356dp</dimen>
     <dimen name="car_fullscreen_user_pod_image_avatar_width">96dp</dimen>
     <dimen name="car_fullscreen_user_pod_image_avatar_height">96dp</dimen>
-    <dimen name="car_padding_4">20dp</dimen>
+
+
+    <!-- Application Bar -->
+    <dimen name="car_app_bar_height">80dp</dimen>
+    <!-- Margin -->
+    <dimen name="car_margin">20dp</dimen>
+    <!-- Lists -->
+    <dimen name="car_single_line_list_item_height">96dp</dimen>
+    <dimen name="car_double_line_list_item_height">@dimen/car_single_line_list_item_height</dimen>
+    <dimen name="car_list_divider_height">1dp</dimen>
+    <!-- The diff between keyline 1 and keyline 3. -->
+    <dimen name="car_keyline_1_keyline_3_diff">88dp</dimen>
+    <dimen name="car_dialog_action_bar_height">@dimen/car_card_action_bar_height</dimen>
+    <dimen name="car_primary_icon_size">44dp</dimen>
+
+    <!-- Text size for car -->
+    <dimen name="car_title_size">32sp</dimen>
+    <dimen name="car_title2_size">32sp</dimen>
+    <dimen name="car_headline1_size">45sp</dimen>
+    <dimen name="car_headline2_size">32sp</dimen>
+    <dimen name="car_headline3_size">24sp</dimen>
+    <dimen name="car_headline4_size">20sp</dimen>
     <dimen name="car_body1_size">32sp</dimen>
-</resources>
\ No newline at end of file
+    <dimen name="car_body2_size">26sp</dimen>
+    <dimen name="car_body3_size">16sp</dimen>
+    <dimen name="car_body4_size">14sp</dimen>
+    <dimen name="car_body5_size">18sp</dimen>
+    <dimen name="car_label1_size">26sp</dimen>
+    <dimen name="car_label2_size">64sp</dimen>
+    <dimen name="car_action1_size">26sp</dimen>
+    <dimen name="car_action2_size">26sp</dimen>
+
+    <!-- Common icon size for car app -->
+    <dimen name="car_icon_size">56dp</dimen>
+
+    <dimen name="car_card_header_height">96dp</dimen>
+    <dimen name="car_card_action_bar_height">96dp</dimen>
+
+    <!-- Paddings -->
+    <dimen name="car_padding_1">4dp</dimen>
+    <dimen name="car_padding_2">10dp</dimen>
+    <dimen name="car_padding_3">16dp</dimen>
+    <dimen name="car_padding_4">28dp</dimen>
+    <dimen name="car_padding_5">32dp</dimen>
+
+    <!-- Radius -->
+    <dimen name="car_radius_1">4dp</dimen>
+    <dimen name="car_radius_2">8dp</dimen>
+    <dimen name="car_radius_3">16dp</dimen>
+    <dimen name="car_radius_5">100dp</dimen>
+
+    <!-- Keylines for content. -->
+    <dimen name="car_keyline_1">48dp</dimen>
+    <dimen name="car_keyline_2">108dp</dimen>
+    <dimen name="car_keyline_3">152dp</dimen>
+    <dimen name="car_keyline_4">182dp</dimen>
+
+    <!-- Buttons -->
+    <dimen name="car_button_height">56dp</dimen>
+    <dimen name="car_button_min_width">158dp</dimen>
+    <dimen name="car_button_horizontal_padding">@dimen/car_padding_4</dimen>
+    <dimen name="car_borderless_button_horizontal_padding">0dp</dimen>
+    <dimen name="car_button_radius">@dimen/car_radius_1</dimen>
+    <dimen name="car_pill_button_size">56dp</dimen>
+
+    <!-- Seekbar -->
+    <dimen name="car_seekbar_height">6dp</dimen>
+    <dimen name="car_seekbar_padding">26dp</dimen>
+    <dimen name="car_seekbar_thumb_size">24dp</dimen>
+    <dimen name="car_seekbar_thumb_stroke">1dp</dimen>
+    <!-- The space between seekbar and text in ListItem. This value is based on car_seekbar_padding.
+         It brings seekbar and text closer for visual balance while maintaining touch area. -->
+    <dimen name="car_seekbar_text_overlap">-20dp</dimen>
+
+    <!-- Progress Bar -->
+    <dimen name="car_progress_bar_height">@dimen/car_seekbar_height</dimen>
+
+</resources>
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index 210f30e..a0b40ed 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -117,6 +117,9 @@
     <!-- Default rounded corner for controls -->
     <dimen name="control_corner_material">2dp</dimen>
 
+    <!-- Size of icon shown beside a preference locked by admin -->
+    <dimen name="restricted_icon_size_material">16dp</dimen>
+
     <dimen name="edit_text_inset_horizontal_material">4dp</dimen>
     <dimen name="edit_text_inset_top_material">10dp</dimen>
     <dimen name="edit_text_inset_bottom_material">7dp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index c751af3..cdaff18 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2909,12 +2909,15 @@
         <public name="opticalInsetBottom" />
         <public name="allowForceDark" />
         <public name="supportsAmbientMode" />
-    </public-group>
-
-    <public-group type="attr" first-id="0x0101058d">
         <!-- @hide For use by platform and tools only. Developers should not specify this value. -->
         <public name="usesNonSdkApi" />
         <public name="minimumUiTimeout" />
+        <public name="isLightTheme" />
+    </public-group>
+
+    <public-group type="drawable" first-id="0x010800b4">
+        <!-- @hide @SystemApi -->
+        <public name="ic_info" />
     </public-group>
 
     <public-group type="style" first-id="0x010302e2">
@@ -2943,6 +2946,11 @@
         <public name="config_sendPackageName" />
     </public-group>
 
+    <public-group type="dimen" first-id="0x01050007">
+        <!-- @hide @SystemApi -->
+        <public name="config_restricted_icon_size" />
+    </public-group>
+
   <!-- ===============================================================
        DO NOT ADD UN-GROUPED ITEMS HERE
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 365e4a4..6d0127a4 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -240,10 +240,31 @@
         <item>Issue registering Wi\u2011Fi calling with your carrier: <xliff:g id="code" example="REG09 - No 911 Address">%1$s</xliff:g></item>
     </string-array>
     <!-- Template for showing mobile network operator name while WFC is active -->
-    <string-array name="wfcSpnFormats">
-        <item>%s</item>
-        <item>%s Wi-Fi Calling</item>
+    <string-array name="wfcSpnFormats" translatable="false">
+        <item>@string/wfcSpnFormat_spn</item>
+        <item>@string/wfcSpnFormat_spn_wifi_calling</item>
+        <item>@string/wfcSpnFormat_wlan_call</item>
+        <item>@string/wfcSpnFormat_spn_wlan_call</item>
+        <item>@string/wfcSpnFormat_spn_wifi</item>
+        <item>@string/wfcSpnFormat_wifi_calling_bar_spn</item>
+        <item>@string/wfcSpnFormat_spn_vowifi</item>
     </string-array>
+
+    <!-- Spn during Wi-Fi Calling: "<operator>" -->
+    <string name="wfcSpnFormat_spn"><xliff:g id="spn" example="Operator">%s</xliff:g></string>
+    <!-- Spn during Wi-Fi Calling: "<operator> Wi-Fi Calling" -->
+    <string name="wfcSpnFormat_spn_wifi_calling"><xliff:g id="spn" example="Operator">%s</xliff:g> Wi-Fi Calling</string>
+    <!-- Spn during Wi-Fi Calling: "WLAN Call" -->
+    <string name="wfcSpnFormat_wlan_call">WLAN Call</string>
+    <!-- Spn during Wi-Fi Calling: "<operator> WLAN Call" -->
+    <string name="wfcSpnFormat_spn_wlan_call"><xliff:g id="spn" example="Operator">%s</xliff:g> WLAN Call</string>
+    <!-- Spn during Wi-Fi Calling: "<operator> Wi-Fi" -->
+    <string name="wfcSpnFormat_spn_wifi"><xliff:g id="spn" example="Operator">%s</xliff:g> Wi-Fi</string>
+    <!-- Spn during Wi-Fi Calling: "WiFi Calling | <operator>" -->
+    <string name="wfcSpnFormat_wifi_calling_bar_spn">WiFi Calling | <xliff:g id="spn" example="Operator">%s</xliff:g></string>
+    <!-- Spn during Wi-Fi Calling: "<operator> VoWifi" -->
+    <string name="wfcSpnFormat_spn_vowifi"><xliff:g id="spn" example="Operator">%s</xliff:g> VoWifi</string>
+
     <!-- WFC, summary for Disabled -->
     <string name="wifi_calling_off_summary">Off</string>
     <!-- WFC, summary for Wi-Fi Preferred -->
@@ -1418,6 +1439,10 @@
     <string name="biometric_not_recognized">Not recognized</string>
     <!-- Accessibility message announced when a fingerprint has been authenticated [CHAR LIMIT=NONE] -->
     <string name="fingerprint_authenticated">Fingerprint authenticated</string>
+    <!-- Accessibility message announced when a face has been authenticated [CHAR LIMIT=NONE] -->
+    <string name="face_authenticated_no_confirmation_required">Face authenticated</string>
+    <!-- Accessibility message announced when a face has been authenticated, but requires the user to press the confirm button [CHAR LIMIT=NONE] -->
+    <string name="face_authenticated_confirmation_required">Face authenticated, please press confirm</string>
 
     <!-- Error message shown when the fingerprint hardware can't be accessed -->
     <string name="fingerprint_error_hw_not_available">Fingerprint hardware not available.</string>
@@ -1495,6 +1520,8 @@
     <string name="face_error_no_space">Face can\u2019t be stored.</string>
     <!-- Generic error message shown when the face operation (e.g. enrollment or authentication) is canceled. Generally not shown to the user. [CHAR LIMIT=50] -->
     <string name="face_error_canceled">Face operation canceled.</string>
+    <!-- Generic error message shown when the face authentication operation is canceled due to user input. Generally not shown to the user [CHAR LIMIT=50] -->
+    <string name="face_error_user_canceled">Face authentication canceled by user.</string>
     <!-- Generic error message shown when the face operation fails because too many attempts have been made. [CHAR LIMIT=50] -->
     <string name="face_error_lockout">Too many attempts. Try again later.</string>
     <!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=50] -->
@@ -4334,6 +4361,9 @@
     <string name="accessibility_shortcut_disabling_service">Accessibility Shortcut turned
         <xliff:g id="service_name" example="TalkBack">%1$s</xliff:g> off</string>
 
+    <!-- Text spoken when accessibility shortcut warning dialog is shown. [CHAR LIMIT=none] -->
+    <string name="accessibility_shortcut_spoken_feedback">Use Accessibility Shortcut again to start the current accessibility feature</string>
+
     <!-- Text appearing in a prompt at the top of UI allowing the user to select a target service or feature to be assigned to the Accessibility button in the navigation bar. -->
     <string name="accessibility_button_prompt_text">Choose a feature to use when you tap the Accessibility button:</string>
 
diff --git a/core/res/res/values/styles_car.xml b/core/res/res/values/styles_car.xml
new file mode 100644
index 0000000..f6ff1b6
--- /dev/null
+++ b/core/res/res/values/styles_car.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <!-- Car text -->
+    <style name="CarBody1">
+        <item name="textStyle">normal</item>
+        <item name="textSize">@dimen/car_body1_size</item>
+        <item name="textColor">@color/car_body1</item>
+    </style>
+
+    <style name="CarBody1.Light">
+        <item name="textColor">@color/car_body1_light</item>
+    </style>
+
+    <style name="CarBody1.Dark">
+        <item name="textColor">@color/car_body2_dark</item>
+    </style>
+
+    <style name="CarBody2">
+        <item name="textStyle">normal</item>
+        <item name="textSize">@dimen/car_body2_size</item>
+        <item name="textColor">@color/car_body2</item>
+    </style>
+
+    <style name="CarBody2.Dark">
+        <item name="textColor">@color/car_body2_dark</item>
+    </style>
+    <style name="CarBody2.Light">
+        <item name="textColor">@color/car_body2_light</item>
+    </style>
+
+    <style name="CarBody3">
+        <item name="textStyle">normal</item>
+        <item name="textSize">@dimen/car_body3_size</item>
+        <item name="textColor">@color/car_body3</item>
+    </style>
+
+    <!-- The smallest styling for body text. The color of this text changes based on the day/night
+         mode. -->
+    <style name="CarBody4">
+        <item name="textStyle">normal</item>
+        <item name="textSize">@dimen/car_body4_size</item>
+        <item name="textColor">@color/car_body4</item>
+    </style>
+
+    <style name="CarAction1">
+        <item name="textStyle">bold</item>
+        <item name="textSize">@dimen/car_action1_size</item>
+        <item name="textColor">@color/car_highlight</item>
+    </style>
+
+    <style name="CarAction1.Dark">
+        <item name="textColor">@color/car_highlight_dark</item>
+    </style>
+    <style name="CarAction1.Light">
+        <item name="textColor">@color/car_highlight_light</item>
+    </style>
+
+    <!-- The styling for title text. The color of this text changes based on day/night mode. -->
+    <style name="CarTitle" >
+        <item name="textStyle">bold</item>
+        <item name="textSize">@dimen/car_title2_size</item>
+        <item name="textColor">@color/car_title</item>
+    </style>
+
+    <!-- Title text that is permanently a dark color. -->
+    <style name="CarTitle.Dark" >
+        <item name="textColor">@color/car_title_dark</item>
+    </style>
+
+    <!-- Title text that is permanently a light color. -->
+    <style name="CarTitle.Light" >
+        <item name="textColor">@color/car_title_light</item>
+    </style>
+
+</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 7b6e064..9f2256a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2429,6 +2429,7 @@
   <java-symbol type="string" name="face_error_timeout" />
   <java-symbol type="array" name="face_error_vendor" />
   <java-symbol type="string" name="face_error_canceled" />
+  <java-symbol type="string" name="face_error_user_canceled" />
   <java-symbol type="string" name="face_error_lockout" />
   <java-symbol type="string" name="face_error_lockout_permanent" />
   <java-symbol type="string" name="face_error_not_enrolled" />
@@ -2446,6 +2447,8 @@
   <java-symbol type="string" name="face_acquired_not_detected" />
   <java-symbol type="array" name="face_acquired_vendor" />
   <java-symbol type="string" name="face_name_template" />
+  <java-symbol type="string" name="face_authenticated_no_confirmation_required" />
+  <java-symbol type="string" name="face_authenticated_confirmation_required" />
 
   <!-- Face config -->
   <java-symbol type="integer" name="config_faceMaxTemplatesPerUser" />
@@ -3083,6 +3086,7 @@
   <java-symbol type="string" name="color_inversion_feature_name" />
   <java-symbol type="string" name="color_correction_feature_name" />
   <java-symbol type="string" name="config_defaultAccessibilityService" />
+  <java-symbol type="string" name="accessibility_shortcut_spoken_feedback" />
 
   <!-- Accessibility Button -->
   <java-symbol type="layout" name="accessibility_button_chooser" />
@@ -3150,7 +3154,9 @@
   <java-symbol type="integer" name="autofill_max_visible_datasets" />
 
   <java-symbol type="style" name="Theme.DeviceDefault.Autofill" />
+  <java-symbol type="style" name="Theme.DeviceDefault.Light.Autofill" />
   <java-symbol type="style" name="Theme.DeviceDefault.Autofill.Save" />
+  <java-symbol type="style" name="Theme.DeviceDefault.Light.Autofill.Save" />
 
   <java-symbol type="dimen" name="notification_big_picture_max_height"/>
   <java-symbol type="dimen" name="notification_big_picture_max_width"/>
@@ -3464,4 +3470,9 @@
   <java-symbol type="integer" name="db_wal_truncate_size" />
   <java-symbol type="integer" name="config_wakeUpDelayDoze" />
   <java-symbol type="string" name="config_dozeWakeScreenSensorType" />
+
+  <!-- For Bluetooth AbsoluteVolume -->
+  <java-symbol type="fraction" name="config_prescaleAbsoluteVolume_index1" />
+  <java-symbol type="fraction" name="config_prescaleAbsoluteVolume_index2" />
+  <java-symbol type="fraction" name="config_prescaleAbsoluteVolume_index3" />
 </resources>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 92096ab..3385527 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -1681,13 +1681,14 @@
     </style>
 
 
-    <!-- @hide DeviceDefault theme for the autofill FillUi -->
-    <style name="Theme.DeviceDefault.Autofill" parent="Theme.Material.Autofill.Light">
-    </style>
+    <!-- @hide DeviceDefault themes for the autofill FillUi -->
+    <style name="Theme.DeviceDefault.Autofill" />
+    <style name="Theme.DeviceDefault.Light.Autofill" />
 
-    <!-- @hide DeviceDefault theme for the autofill SaveUi -->
-    <style name="Theme.DeviceDefault.Autofill.Save" parent="Theme.Material.Autofill.Save.Light">
-    </style>
+    <!-- @hide DeviceDefault theme for the autofill SaveUi. NOTE: it must be a .Panel so the dialog
+         is shown at the bottom of the screen  -->
+    <style name="Theme.DeviceDefault.Autofill.Save" parent="Theme.DeviceDefault.Panel"/>
+    <style name="Theme.DeviceDefault.Light.Autofill.Save" parent="Theme.DeviceDefault.Light.Panel"/>
 
     <!-- DeviceDefault theme for the default system theme.  -->
     <style name="Theme.DeviceDefault.System" parent="Theme.DeviceDefault.Light.DarkActionBar" />
@@ -1715,4 +1716,10 @@
         <item name="colorAccent">@color/accent_device_default_dark</item>
     </style>
 
+    <style name="Theme.DeviceDefault.Light.Dialog.Alert.UserSwitchingDialog" parent="Theme.DeviceDefault.NoActionBar.Fullscreen">
+        <item name="colorBackground">@color/background_device_default_light</item>
+        <item name="colorBackgroundFloating">@color/background_device_default_light</item>
+        <item name="layout_gravity">center</item>
+    </style>
+
 </resources>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index b3e33d5..ccaf041 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -1418,24 +1418,4 @@
         <item name="colorSecondary">@color/secondary_material_settings</item>
     </style>
 
-    <!-- @hide -->
-    <style name="Theme.Material.Autofill" parent="Theme.Material">
-        <item name="colorBackground">@color/autofill_background_material_dark</item>
-    </style>
-
-    <!-- @hide -->
-    <style name="Theme.Material.Autofill.Light" parent="Theme.Material.Light">
-        <item name="colorBackground">@color/autofill_background_material_light</item>
-    </style>
-
-    <!-- @hide -->
-    <style name="Theme.Material.Autofill.Save" parent="Theme.Material.Panel">
-        <item name="colorBackground">@color/autofill_background_material_dark</item>
-    </style>
-
-    <!-- @hide -->
-    <style name="Theme.Material.Autofill.Save.Light" parent="Theme.Material.Light.Panel">
-        <item name="colorBackground">@color/autofill_background_material_light</item>
-    </style>
-
 </resources>
diff --git a/core/res/res/xml/default_zen_mode_config.xml b/core/res/res/xml/default_zen_mode_config.xml
index cb4e5c4..6cf6a82 100644
--- a/core/res/res/xml/default_zen_mode_config.xml
+++ b/core/res/res/xml/default_zen_mode_config.xml
@@ -18,13 +18,17 @@
 -->
 
 <!-- Default configuration for zen mode.  See android.service.notification.ZenModeConfig. -->
-<zen version="7">
+<zen version="8">
     <allow alarms="true" media="true" system="false" calls="true" callsFrom="2" messages="false"
            reminders="false" events="false" repeatCallers="true" />
-
+    <automatic ruleId="EVENTS_DEFAULT_RULE" enabled="false" snoozing="false" name="Event" zen="1"
+               component="android/com.android.server.notification.EventConditionProvider"
+               conditionId="condition://android/event?userId=-10000&amp;calendar=&amp;reply=1"/>
+    <automatic ruleId="EVERY_NIGHT_DEFAULT_RULE" enabled="false" snoozing="false" name="Sleeping"
+               zen="1" component="android/com.android.server.notification.ScheduleConditionProvider"
+               conditionId="condition://android/schedule?days=1.2.3.4.5.6.7&amp;start=22.0&amp;end=7.0&amp;exitAtAlarm=true"/>
     <!-- all visual effects that exist as of P -->
     <disallow visualEffects="511" />
-
     <!-- whether there are notification channels that can bypass dnd -->
     <state areChannelsBypassingDnd="false" />
 </zen>
diff --git a/core/tests/coretests/src/android/content/ContentProviderTest.java b/core/tests/coretests/src/android/content/ContentProviderTest.java
new file mode 100644
index 0000000..2142f27
--- /dev/null
+++ b/core/tests/coretests/src/android/content/ContentProviderTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.content;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.withSettings;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ProviderInfo;
+import android.net.Uri;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+
+@RunWith(AndroidJUnit4.class)
+public class ContentProviderTest {
+
+    private Context mContext;
+    private ContentProvider mCp;
+
+    private ApplicationInfo mProviderApp;
+    private ProviderInfo mProvider;
+
+    @Before
+    public void setUp() {
+        mProviderApp = new ApplicationInfo();
+        mProviderApp.uid = 10001;
+
+        mProvider = new ProviderInfo();
+        mProvider.authority = "com.example";
+        mProvider.applicationInfo = mProviderApp;
+
+        mContext = mock(Context.class);
+
+        mCp = mock(ContentProvider.class, withSettings().defaultAnswer(Answers.CALLS_REAL_METHODS));
+        mCp.attachInfo(mContext, mProvider);
+    }
+
+    @Test
+    public void testValidateIncomingUri_Normal() throws Exception {
+        assertEquals(Uri.parse("content://com.example/"),
+                mCp.validateIncomingUri(Uri.parse("content://com.example/")));
+        assertEquals(Uri.parse("content://com.example/foo/bar"),
+                mCp.validateIncomingUri(Uri.parse("content://com.example/foo/bar")));
+        assertEquals(Uri.parse("content://com.example/foo%2Fbar"),
+                mCp.validateIncomingUri(Uri.parse("content://com.example/foo%2Fbar")));
+        assertEquals(Uri.parse("content://com.example/foo%2F%2Fbar"),
+                mCp.validateIncomingUri(Uri.parse("content://com.example/foo%2F%2Fbar")));
+    }
+
+    @Test
+    public void testValidateIncomingUri_Shady() throws Exception {
+        assertEquals(Uri.parse("content://com.example/"),
+                mCp.validateIncomingUri(Uri.parse("content://com.example//")));
+        assertEquals(Uri.parse("content://com.example/foo/bar/"),
+                mCp.validateIncomingUri(Uri.parse("content://com.example//foo//bar//")));
+        assertEquals(Uri.parse("content://com.example/foo/bar/"),
+                mCp.validateIncomingUri(Uri.parse("content://com.example/foo///bar/")));
+        assertEquals(Uri.parse("content://com.example/foo%2F%2Fbar/baz"),
+                mCp.validateIncomingUri(Uri.parse("content://com.example/foo%2F%2Fbar//baz")));
+    }
+
+    @Test
+    public void testValidateIncomingUri_NonPath() throws Exception {
+        // We only touch paths; queries and fragments are left intact
+        assertEquals(Uri.parse("content://com.example/foo/bar?foo=b//ar#foo=b//ar"),
+                mCp.validateIncomingUri(
+                        Uri.parse("content://com.example/foo/bar?foo=b//ar#foo=b//ar")));
+    }
+}
diff --git a/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
new file mode 100644
index 0000000..7218b3a2
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content.pm;
+
+import static android.content.pm.PackageBuilder.builder;
+import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_BASE;
+import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_MANAGER;
+
+import android.os.Build;
+import android.support.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Test for {@link AndroidHidlUpdater}
+ */
+@SmallTest
+@RunWith(JUnit4.class)
+public class AndroidHidlUpdaterTest extends PackageSharedLibraryUpdaterTest {
+
+    private static final String OTHER_LIBRARY = "other.library";
+
+    @Test
+    public void targeted_at_O() {
+        PackageBuilder before = builder()
+                .targetSdkVersion(Build.VERSION_CODES.O);
+
+        // Should add both HIDL libraries
+        PackageBuilder after = builder()
+                .targetSdkVersion(Build.VERSION_CODES.O)
+                .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE);
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_O_not_empty_usesLibraries() {
+        PackageBuilder before = builder()
+                .targetSdkVersion(Build.VERSION_CODES.O)
+                .requiredLibraries(OTHER_LIBRARY);
+
+        // The hidl jars should be added at the start of the list because it
+        // is not on the bootclasspath and the package targets pre-P.
+        PackageBuilder after = builder()
+                .targetSdkVersion(Build.VERSION_CODES.O)
+                .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE, OTHER_LIBRARY);
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_O_in_usesLibraries() {
+        PackageBuilder before = builder()
+                .targetSdkVersion(Build.VERSION_CODES.O)
+                .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE);
+
+        // No change is required because although the HIDL libraries has been removed from
+        // the bootclasspath the package explicitly requests it.
+        checkBackwardsCompatibility(before, before);
+    }
+
+    @Test
+    public void in_usesLibraries() {
+        PackageBuilder before = builder().requiredLibraries(ANDROID_HIDL_BASE);
+
+        // No change is required because the package explicitly requests the HIDL libraries
+        // and is targeted at the current version so does not need backwards compatibility.
+        checkBackwardsCompatibility(before, before);
+    }
+
+    @Test
+    public void in_usesOptionalLibraries() {
+        PackageBuilder before = builder().optionalLibraries(ANDROID_HIDL_BASE);
+
+        // No change is required because the package explicitly requests the HIDL libraries
+        // and is targeted at the current version so does not need backwards compatibility.
+        checkBackwardsCompatibility(before, before);
+    }
+
+    private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) {
+        checkBackwardsCompatibility(before, after, AndroidHidlUpdater::new);
+    }
+}
diff --git a/core/tests/coretests/src/android/graphics/PaintTest.java b/core/tests/coretests/src/android/graphics/PaintTest.java
index 2f28606..b5ed01f 100644
--- a/core/tests/coretests/src/android/graphics/PaintTest.java
+++ b/core/tests/coretests/src/android/graphics/PaintTest.java
@@ -186,44 +186,28 @@
         Paint p = new Paint();
 
         final int count = end - start;
-        final float[][] advanceArrays = new float[4][count];
-
-        final float advance = p.getTextRunAdvances(str, start, end, contextStart, contextEnd,
-                isRtl, advanceArrays[0], 0);
-
+        final int contextCount = contextEnd - contextStart;
+        final float[][] advanceArrays = new float[2][count];
         char chars[] = str.toCharArray();
-        final float advance_c = p.getTextRunAdvances(chars, start, count, contextStart,
-                contextEnd - contextStart, isRtl, advanceArrays[1], 0);
-        assertEquals(advance, advance_c, 1.0f);
-
+        final float advance = p.getTextRunAdvances(chars, start, count,
+                contextStart, contextCount, isRtl, advanceArrays[0], 0);
         for (int c = 1; c < count; ++c) {
-            final float firstPartAdvance = p.getTextRunAdvances(str, start, start + c,
-                    contextStart, contextEnd, isRtl, advanceArrays[2], 0);
-            final float secondPartAdvance = p.getTextRunAdvances(str, start + c, end,
-                    contextStart, contextEnd, isRtl, advanceArrays[2], c);
+            final float firstPartAdvance = p.getTextRunAdvances(chars, start, c,
+                    contextStart, contextCount, isRtl, advanceArrays[1], 0);
+            final float secondPartAdvance = p.getTextRunAdvances(chars, start + c, count - c,
+                    contextStart, contextCount, isRtl, advanceArrays[1], c);
             assertEquals(advance, firstPartAdvance + secondPartAdvance, 1.0f);
 
-
-            final float firstPartAdvance_c = p.getTextRunAdvances(chars, start, c,
-                    contextStart, contextEnd - contextStart, isRtl, advanceArrays[3], 0);
-            final float secondPartAdvance_c = p.getTextRunAdvances(chars, start + c,
-                    count - c, contextStart, contextEnd - contextStart, isRtl,
-                    advanceArrays[3], c);
-            assertEquals(advance, firstPartAdvance_c + secondPartAdvance_c, 1.0f);
-            assertEquals(firstPartAdvance, firstPartAdvance_c, 1.0f);
-            assertEquals(secondPartAdvance, secondPartAdvance_c, 1.0f);
-
-            for (int i = 1; i < advanceArrays.length; i++) {
-                for (int j = 0; j < count; j++) {
-                    assertEquals(advanceArrays[0][j], advanceArrays[i][j], 1.0f);
-                }
+            for (int j = 0; j < count; j++) {
+                assertEquals(advanceArrays[0][j], advanceArrays[1][j], 1.0f);
             }
 
+
             // Compare results with measureText, getRunAdvance, and getTextWidths.
             if (compareWithOtherMethods && start == contextStart && end == contextEnd) {
                 assertEquals(advance, p.measureText(str, start, end), 1.0f);
                 assertEquals(advance, p.getRunAdvance(
-                        str, start, end, contextStart, contextEnd, isRtl, end), 1.0f);
+                        chars, start, count, contextStart, contextCount, isRtl, end), 1.0f);
 
                 final float[] widths = new float[count];
                 p.getTextWidths(str, start, end, widths);
@@ -236,19 +220,7 @@
 
     public void testGetTextRunAdvances_invalid() {
         Paint p = new Paint();
-        String text = "test";
-
-        try {
-            p.getTextRunAdvances((String)null, 0, 0, 0, 0, false, null, 0);
-            fail("Should throw an IllegalArgumentException.");
-        } catch (IllegalArgumentException e) {
-        }
-
-        try {
-            p.getTextRunAdvances((CharSequence)null, 0, 0, 0, 0, false, null, 0);
-            fail("Should throw an IllegalArgumentException.");
-        } catch (IllegalArgumentException e) {
-        }
+        char[] text = "test".toCharArray();
 
         try {
             p.getTextRunAdvances((char[])null, 0, 0, 0, 0, false, null, 0);
@@ -257,50 +229,43 @@
         }
 
         try {
-            p.getTextRunAdvances(text, 0, text.length(), 0, text.length(), false,
-                    new float[text.length() - 1], 0);
+            p.getTextRunAdvances(text, 0, text.length, 0, text.length, false,
+                    new float[text.length - 1], 0);
             fail("Should throw an IndexOutOfBoundsException.");
         } catch (IndexOutOfBoundsException e) {
         }
 
         try {
-            p.getTextRunAdvances(text, 0, text.length(), 0, text.length(), false,
-                    new float[text.length()], 1);
+            p.getTextRunAdvances(text, 0, text.length, 0, text.length, false,
+                    new float[text.length], 1);
             fail("Should throw an IndexOutOfBoundsException.");
         } catch (IndexOutOfBoundsException e) {
         }
 
         // 0 > contextStart
         try {
-            p.getTextRunAdvances(text, 0, text.length(), -1, text.length(), false, null, 0);
+            p.getTextRunAdvances(text, 0, text.length, -1, text.length, false, null, 0);
             fail("Should throw an IndexOutOfBoundsException.");
         } catch (IndexOutOfBoundsException e) {
         }
 
         // contextStart > start
         try {
-            p.getTextRunAdvances(text, 0, text.length(), 1, text.length(), false, null, 0);
-            fail("Should throw an IndexOutOfBoundsException.");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        // start > end
-        try {
-            p.getTextRunAdvances(text, 1, 0, 0, text.length(), false, null, 0);
+            p.getTextRunAdvances(text, 0, text.length, 1, text.length, false, null, 0);
             fail("Should throw an IndexOutOfBoundsException.");
         } catch (IndexOutOfBoundsException e) {
         }
 
         // end > contextEnd
         try {
-            p.getTextRunAdvances(text, 0, text.length(), 0, text.length() - 1, false, null, 0);
+            p.getTextRunAdvances(text, 0, text.length, 0, text.length - 1, false, null, 0);
             fail("Should throw an IndexOutOfBoundsException.");
         } catch (IndexOutOfBoundsException e) {
         }
 
         // contextEnd > text.length
         try {
-            p.getTextRunAdvances(text, 0, text.length(), 0, text.length() + 1, false, null, 0);
+            p.getTextRunAdvances(text, 0, text.length, 0, text.length + 1, false, null, 0);
             fail("Should throw an IndexOutOfBoundsException.");
         } catch (IndexOutOfBoundsException e) {
         }
diff --git a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
index 1c4039b..3ce2589 100644
--- a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
+++ b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
@@ -44,7 +44,7 @@
 import java.nio.charset.Charset;
 import java.nio.file.Files;
 import java.nio.file.StandardCopyOption;
-import java.util.HashSet;
+import java.util.ArrayList;
 import java.util.Locale;
 
 @SmallTest
@@ -112,7 +112,7 @@
 
     private static void buildSystemFallback(String xml,
             ArrayMap<String, Typeface> fontMap, ArrayMap<String, FontFamily[]> fallbackMap) {
-        final HashSet<Font> availableFonts = new HashSet<>();
+        final ArrayList<Font> availableFonts = new ArrayList<>();
         try (FileOutputStream fos = new FileOutputStream(TEST_FONTS_XML)) {
             fos.write(xml.getBytes(Charset.forName("UTF-8")));
         } catch (IOException e) {
@@ -127,7 +127,7 @@
     public void testBuildSystemFallback() {
         final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
         final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
-        final HashSet<Font> availableFonts = new HashSet<>();
+        final ArrayList<Font> availableFonts = new ArrayList<>();
 
         final FontConfig.Alias[] aliases = SystemFonts.buildSystemFallback(SYSTEM_FONTS_XML,
                 SYSTEM_FONT_DIR, fallbackMap, availableFonts);
diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
index 9c9f11b..20fe162 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -17,6 +17,22 @@
 package android.os;
 
 import static android.os.FileUtils.roundStorageSize;
+import static android.os.FileUtils.translateModePfdToPosix;
+import static android.os.FileUtils.translateModePosixToPfd;
+import static android.os.FileUtils.translateModePosixToString;
+import static android.os.FileUtils.translateModeStringToPosix;
+import static android.os.ParcelFileDescriptor.MODE_APPEND;
+import static android.os.ParcelFileDescriptor.MODE_CREATE;
+import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
+import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
+import static android.os.ParcelFileDescriptor.MODE_TRUNCATE;
+import static android.os.ParcelFileDescriptor.MODE_WRITE_ONLY;
+import static android.system.OsConstants.O_APPEND;
+import static android.system.OsConstants.O_CREAT;
+import static android.system.OsConstants.O_RDONLY;
+import static android.system.OsConstants.O_RDWR;
+import static android.system.OsConstants.O_TRUNC;
+import static android.system.OsConstants.O_WRONLY;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
 import static android.text.format.DateUtils.WEEK_IN_MILLIS;
@@ -476,6 +492,32 @@
         assertEquals(G64, roundStorageSize(G32 + 1));
     }
 
+    @Test
+    public void testTranslateMode() throws Exception {
+        assertTranslate("r", O_RDONLY, MODE_READ_ONLY);
+
+        assertTranslate("rw", O_RDWR | O_CREAT,
+                MODE_READ_WRITE | MODE_CREATE);
+        assertTranslate("rwt", O_RDWR | O_CREAT | O_TRUNC,
+                MODE_READ_WRITE | MODE_CREATE | MODE_TRUNCATE);
+        assertTranslate("rwa", O_RDWR | O_CREAT | O_APPEND,
+                MODE_READ_WRITE | MODE_CREATE | MODE_APPEND);
+
+        assertTranslate("w", O_WRONLY | O_CREAT,
+                MODE_WRITE_ONLY | MODE_CREATE | MODE_CREATE);
+        assertTranslate("wt", O_WRONLY | O_CREAT | O_TRUNC,
+                MODE_WRITE_ONLY | MODE_CREATE | MODE_TRUNCATE);
+        assertTranslate("wa", O_WRONLY | O_CREAT | O_APPEND,
+                MODE_WRITE_ONLY | MODE_CREATE | MODE_APPEND);
+    }
+
+    private static void assertTranslate(String string, int posix, int pfd) {
+        assertEquals(posix, translateModeStringToPosix(string));
+        assertEquals(string, translateModePosixToString(posix));
+        assertEquals(pfd, translateModePosixToPfd(posix));
+        assertEquals(posix, translateModePfdToPosix(pfd));
+    }
+
     private static void assertNameEquals(String expected, File actual) {
         assertEquals(expected, actual.getName());
     }
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index e84aed1..fee470d 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -241,7 +241,6 @@
                     Settings.Global.EUICC_SUPPORTED_COUNTRIES,
                     Settings.Global.EUICC_FACTORY_RESET_TIMEOUT_MILLIS,
                     Settings.Global.FANCY_IME_ANIMATIONS,
-                    Settings.Global.FASTER_EMERGENCY_PHONE_CALL_ENABLED,
                     Settings.Global.FORCE_ALLOW_ON_EXTERNAL,
                     Settings.Global.FORCED_APP_STANDBY_ENABLED,
                     Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED,
diff --git a/core/tests/coretests/src/android/text/FontFallbackSetup.java b/core/tests/coretests/src/android/text/FontFallbackSetup.java
index 355be61..898e78c 100644
--- a/core/tests/coretests/src/android/text/FontFallbackSetup.java
+++ b/core/tests/coretests/src/android/text/FontFallbackSetup.java
@@ -33,7 +33,7 @@
 import java.nio.charset.Charset;
 import java.nio.file.Files;
 import java.nio.file.StandardCopyOption;
-import java.util.HashSet;
+import java.util.ArrayList;
 
 public class FontFallbackSetup implements AutoCloseable {
     private final String[] mTestFontFiles;
@@ -76,7 +76,7 @@
         }
 
         final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
-        final HashSet<Font> availableFonts = new HashSet<>();
+        final ArrayList<Font> availableFonts = new ArrayList<>();
         final FontConfig.Alias[] aliases = SystemFonts.buildSystemFallback(testFontsXml,
                 mTestFontsDir, fallbackMap, availableFonts);
         Typeface.initSystemDefaultTypefaces(mFontMap, fallbackMap, aliases);
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
index 922b79a..69d2828 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
@@ -57,7 +57,7 @@
 
     // The number of flags held in boolean properties. Their values should also be double-checked
     // in the methods above.
-    private static final int NUM_BOOLEAN_PROPERTIES = 17;
+    private static final int NUM_BOOLEAN_PROPERTIES = 18;
 
     @Test
     public void testStandardActions_serializationFlagIsValid() {
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodManagerTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodManagerTest.java
new file mode 100644
index 0000000..55e5e36
--- /dev/null
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodManagerTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.inputmethod;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.WindowManager;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class InputMethodManagerTest {
+    @Test
+    public void testPrivateApiGetInstance() throws Exception {
+        final InputMethodManager globalImm = InputMethodManager.getInstance();
+        assertNotNull("InputMethodManager.getInstance() still needs to work due to"
+                + " @UnsupportedAppUsage", globalImm);
+        assertEquals("InputMethodManager.peekInstance() still needs to work due to"
+                + " @UnsupportedAppUsage", globalImm, InputMethodManager.peekInstance());
+
+        final Context testContext = InstrumentationRegistry.getInstrumentation()
+                .getTargetContext();
+
+        final WindowManager wm = testContext.getSystemService(WindowManager.class);
+        final Context defaultDisplayContext =
+                testContext.createDisplayContext(wm.getDefaultDisplay());
+        final InputMethodManager imm =
+                defaultDisplayContext.getSystemService(InputMethodManager.class);
+        assertEquals("InputMethodManager.getInstance() always returns the instance for the default"
+                + " display.", globalImm, imm);
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
index f3e10e0..a302657 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
@@ -16,6 +16,31 @@
 
 package com.android.internal.accessibility;
 
+import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN;
+import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED;
+import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN;
+import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assert.fail;
+import static org.mockito.AdditionalMatchers.aryEq;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.app.AlertDialog;
 import android.content.ComponentName;
@@ -25,11 +50,14 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
+import android.media.Ringtone;
 import android.os.Handler;
+import android.os.Message;
 import android.os.Vibrator;
 import android.provider.Settings;
+import android.speech.tts.TextToSpeech;
+import android.speech.tts.Voice;
 import android.support.test.runner.AndroidJUnit4;
-
 import android.test.mock.MockContentResolver;
 import android.text.TextUtils;
 import android.view.Window;
@@ -37,9 +65,10 @@
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.IAccessibilityManager;
 import android.widget.Toast;
+
 import com.android.internal.R;
-import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.internal.accessibility.AccessibilityShortcutController.FrameworkObjectProvider;
+import com.android.internal.util.test.FakeSettingsProvider;
 
 import org.junit.After;
 import org.junit.Before;
@@ -48,31 +77,12 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
 
 import java.lang.reflect.Field;
 import java.util.Collections;
 import java.util.Map;
 
-import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN;
-import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED;
-import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN;
-import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-
-import static org.junit.Assert.fail;
-import static org.mockito.AdditionalMatchers.aryEq;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyObject;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
 
 @RunWith(AndroidJUnit4.class)
 public class AccessibilityShortcutControllerTest {
@@ -102,6 +112,9 @@
     private @Mock Vibrator mVibrator;
     private @Mock ApplicationInfo mApplicationInfo;
     private @Mock PackageManager mPackageManager;
+    private @Mock TextToSpeech mTextToSpeech;
+    private @Mock Voice mVoice;
+    private @Mock Ringtone mRingtone;
 
     private MockContentResolver mContentResolver;
     private WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams();
@@ -137,6 +150,9 @@
         when(mFrameworkObjectProvider.makeToastFromText(eq(mContext), anyObject(), anyInt()))
                 .thenReturn(mToast);
         when(mFrameworkObjectProvider.getSystemUiContext()).thenReturn(mContext);
+        when(mFrameworkObjectProvider.getTextToSpeech(eq(mContext), any()))
+                .thenReturn(mTextToSpeech);
+        when(mFrameworkObjectProvider.getRingtone(eq(mContext), any())).thenReturn(mRingtone);
 
         when(mResources.getString(anyInt())).thenReturn("Howdy %s");
         when(mResources.getIntArray(anyInt())).thenReturn(VIBRATOR_PATTERN_INT);
@@ -172,6 +188,8 @@
             throw new RuntimeException("Unable to set mWindowAttributes", e);
         }
         when(mAlertDialog.getWindow()).thenReturn(window);
+
+        when(mTextToSpeech.getVoice()).thenReturn(mVoice);
     }
 
     @After
@@ -308,8 +326,10 @@
                 mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0));
         verify(mResources).getString(R.string.accessibility_shortcut_toogle_warning);
         verify(mAlertDialog).show();
-        verify(mAccessibilityManagerService).getInstalledAccessibilityServiceList(anyInt());
+        verify(mAccessibilityManagerService, atLeastOnce()).getInstalledAccessibilityServiceList(
+                anyInt());
         verify(mAccessibilityManagerService, times(0)).performAccessibilityShortcut();
+        verify(mFrameworkObjectProvider, times(0)).getTextToSpeech(any(), any());
     }
 
     @Test
@@ -434,6 +454,49 @@
         verify(mAccessibilityManagerService).performAccessibilityShortcut();
     }
 
+    @Test
+    public void testOnAccessibilityShortcut_showsWarningDialog_shouldTtsSpokenPrompt() {
+        configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
+        configureValidShortcutService();
+        configureTtsSpokenPromptEnabled();
+        configureHandlerCallbackInvocation();
+        AccessibilityShortcutController accessibilityShortcutController = getController();
+        Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
+        accessibilityShortcutController.performAccessibilityShortcut();
+
+        verify(mAlertDialog).show();
+        ArgumentCaptor<TextToSpeech.OnInitListener> onInitCap = ArgumentCaptor.forClass(
+                TextToSpeech.OnInitListener.class);
+        verify(mFrameworkObjectProvider).getTextToSpeech(any(), onInitCap.capture());
+        onInitCap.getValue().onInit(TextToSpeech.SUCCESS);
+        verify(mTextToSpeech).speak(any(), eq(TextToSpeech.QUEUE_FLUSH), any(), any());
+        ArgumentCaptor<DialogInterface.OnDismissListener> onDismissCap = ArgumentCaptor.forClass(
+                DialogInterface.OnDismissListener.class);
+        verify(mAlertDialog).setOnDismissListener(onDismissCap.capture());
+        onDismissCap.getValue().onDismiss(mAlertDialog);
+        verify(mTextToSpeech).shutdown();
+        verify(mRingtone, times(0)).play();
+    }
+
+    @Test
+    public void testOnAccessibilityShortcut_showsWarningDialog_ttsInitFail_noSpokenPrompt() {
+        configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
+        configureValidShortcutService();
+        configureTtsSpokenPromptEnabled();
+        configureHandlerCallbackInvocation();
+        AccessibilityShortcutController accessibilityShortcutController = getController();
+        Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
+        accessibilityShortcutController.performAccessibilityShortcut();
+
+        verify(mAlertDialog).show();
+        ArgumentCaptor<TextToSpeech.OnInitListener> onInitCap = ArgumentCaptor.forClass(
+                TextToSpeech.OnInitListener.class);
+        verify(mFrameworkObjectProvider).getTextToSpeech(any(), onInitCap.capture());
+        onInitCap.getValue().onInit(TextToSpeech.ERROR);
+        verify(mTextToSpeech, times(0)).speak(any(), anyInt(), any(), any());
+        verify(mRingtone).play();
+    }
+
     private void configureNoShortcutService() {
         Settings.Secure.putString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, "");
     }
@@ -481,6 +544,19 @@
                 mContentResolver, ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, lockscreen ? 1 : 0);
     }
 
+    private void configureTtsSpokenPromptEnabled() {
+        mServiceInfo.flags |= AccessibilityServiceInfo
+                .FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK;
+    }
+
+    private void configureHandlerCallbackInvocation() {
+        doAnswer((InvocationOnMock invocation) -> {
+            Message m = (Message) invocation.getArguments()[0];
+            m.getCallback().run();
+            return true;
+        }).when(mHandler).sendMessageAtTime(any(), anyLong());
+    }
+
     private AccessibilityShortcutController getController() {
         AccessibilityShortcutController accessibilityShortcutController =
                 new AccessibilityShortcutController(mContext, mHandler, 0);
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/SubtypeLocaleUtilsTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/SubtypeLocaleUtilsTest.java
new file mode 100644
index 0000000..8179328
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/SubtypeLocaleUtilsTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.inputmethod;
+
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Locale;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SubtypeLocaleUtilsTest {
+    private static final Locale LOCALE_EN = new Locale("en");
+    private static final Locale LOCALE_EN_US = new Locale("en", "US");
+    private static final Locale LOCALE_EN_GB = new Locale("en", "GB");
+    private static final Locale LOCALE_EN_IN = new Locale("en", "IN");
+    private static final Locale LOCALE_FIL = new Locale("fil");
+    private static final Locale LOCALE_FIL_PH = new Locale("fil", "PH");
+    private static final Locale LOCALE_JA = new Locale("ja");
+    private static final Locale LOCALE_JA_JP = new Locale("ja", "JP");
+    private static final Locale LOCALE_TH = new Locale("ht");
+    private static final Locale LOCALE_TH_TH = new Locale("ht", "TH");
+    private static final Locale LOCALE_TH_TH_TH = new Locale("ht", "TH", "TH");
+
+    @Test
+    public void testConstructLocaleFromString() throws Exception {
+        assertEquals(new Locale("en"), SubtypeLocaleUtils.constructLocaleFromString("en"));
+        assertEquals(new Locale("en", "US"), SubtypeLocaleUtils.constructLocaleFromString("en_US"));
+        assertEquals(new Locale("en", "US", "POSIX"),
+                SubtypeLocaleUtils.constructLocaleFromString("en_US_POSIX"));
+
+        // Special rewrite rule for "tl" for versions of Android earlier than Lollipop that did not
+        // support three letter language codes, and used "tl" (Tagalog) as the language string for
+        // "fil" (Filipino).
+        assertEquals(new Locale("fil"), SubtypeLocaleUtils.constructLocaleFromString("tl"));
+        assertEquals(new Locale("fil", "PH"),
+                SubtypeLocaleUtils.constructLocaleFromString("tl_PH"));
+        assertEquals(new Locale("fil", "PH", "POSIX"),
+                SubtypeLocaleUtils.constructLocaleFromString("tl_PH_POSIX"));
+
+        // So far rejecting an invalid/unexpected locale string is out of the scope of this method.
+        assertEquals(new Locale("a"), SubtypeLocaleUtils.constructLocaleFromString("a"));
+        assertEquals(new Locale("a b c"), SubtypeLocaleUtils.constructLocaleFromString("a b c"));
+        assertEquals(new Locale("en-US"), SubtypeLocaleUtils.constructLocaleFromString("en-US"));
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
index 0eb3d06..0c8dd9d 100644
--- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
@@ -21,6 +21,7 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
+import android.os.Message;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
@@ -74,14 +75,17 @@
     public void testSingleMessageDispatched() {
         TestableLooperStats looperStats = new TestableLooperStats(1, 100);
 
+        Message message = mHandlerFirst.obtainMessage(1000);
+        message.workSourceUid = 1000;
         Object token = looperStats.messageDispatchStarting();
         looperStats.tickRealtime(100);
         looperStats.tickThreadTime(10);
-        looperStats.messageDispatched(token, mHandlerFirst.obtainMessage(1000));
+        looperStats.messageDispatched(token, message);
 
         List<LooperStats.ExportedEntry> entries = looperStats.getEntries();
         assertThat(entries).hasSize(1);
         LooperStats.ExportedEntry entry = entries.get(0);
+        assertThat(entry.workSourceUid).isEqualTo(1000);
         assertThat(entry.threadName).isEqualTo("TestThread1");
         assertThat(entry.handlerClassName).isEqualTo(
                 "com.android.internal.os.LooperStatsTest$TestHandlerFirst");
@@ -100,15 +104,17 @@
     public void testThrewException() {
         TestableLooperStats looperStats = new TestableLooperStats(1, 100);
 
+        Message message = mHandlerFirst.obtainMessage(7);
+        message.workSourceUid = 123;
         Object token = looperStats.messageDispatchStarting();
         looperStats.tickRealtime(100);
         looperStats.tickThreadTime(10);
-        looperStats.dispatchingThrewException(token, mHandlerFirst.obtainMessage(7),
-                new ArithmeticException());
+        looperStats.dispatchingThrewException(token, message, new ArithmeticException());
 
         List<LooperStats.ExportedEntry> entries = looperStats.getEntries();
         assertThat(entries).hasSize(1);
         LooperStats.ExportedEntry entry = entries.get(0);
+        assertThat(entry.workSourceUid).isEqualTo(123);
         assertThat(entry.threadName).isEqualTo("TestThread1");
         assertThat(entry.handlerClassName).isEqualTo(
                 "com.android.internal.os.LooperStatsTest$TestHandlerFirst");
@@ -146,31 +152,39 @@
         looperStats.messageDispatched(token3, mHandlerSecond.obtainMessage().setCallback(() -> {
         }));
 
-        // Contributes to entry1.
+        // Will not be sampled so does not contribute to any entries.
         Object token4 = looperStats.messageDispatchStarting();
+        looperStats.tickRealtime(10);
+        looperStats.tickThreadTime(10);
+        looperStats.messageDispatched(token4, mHandlerSecond.obtainMessage(0));
+
+        // Contributes to entry1.
+        Object token5 = looperStats.messageDispatchStarting();
         looperStats.tickRealtime(100);
         looperStats.tickThreadTime(100);
-        looperStats.messageDispatched(token4, mHandlerAnonymous.obtainMessage(1));
+        looperStats.messageDispatched(token5, mHandlerAnonymous.obtainMessage(1));
 
         List<LooperStats.ExportedEntry> entries = looperStats.getEntries();
         assertThat(entries).hasSize(3);
         entries.sort(Comparator.comparing(e -> e.handlerClassName));
 
-        // Captures data for token4 call.
+        // Captures data for token5 call.
         LooperStats.ExportedEntry entry1 = entries.get(0);
+        assertThat(entry1.workSourceUid).isEqualTo(-1);
         assertThat(entry1.threadName).isEqualTo("TestThread1");
         assertThat(entry1.handlerClassName).isEqualTo("com.android.internal.os.LooperStatsTest$1");
         assertThat(entry1.messageName).isEqualTo("0x1" /* 1 in hex */);
         assertThat(entry1.messageCount).isEqualTo(1);
-        assertThat(entry1.recordedMessageCount).isEqualTo(0);
+        assertThat(entry1.recordedMessageCount).isEqualTo(1);
         assertThat(entry1.exceptionCount).isEqualTo(0);
-        assertThat(entry1.totalLatencyMicros).isEqualTo(0);
-        assertThat(entry1.maxLatencyMicros).isEqualTo(0);
-        assertThat(entry1.cpuUsageMicros).isEqualTo(0);
-        assertThat(entry1.maxCpuUsageMicros).isEqualTo(0);
+        assertThat(entry1.totalLatencyMicros).isEqualTo(100);
+        assertThat(entry1.maxLatencyMicros).isEqualTo(100);
+        assertThat(entry1.cpuUsageMicros).isEqualTo(100);
+        assertThat(entry1.maxCpuUsageMicros).isEqualTo(100);
 
         // Captures data for token1 and token2 calls.
         LooperStats.ExportedEntry entry2 = entries.get(1);
+        assertThat(entry2.workSourceUid).isEqualTo(-1);
         assertThat(entry2.threadName).isEqualTo("TestThread1");
         assertThat(entry2.handlerClassName).isEqualTo(
                 "com.android.internal.os.LooperStatsTest$TestHandlerFirst");
@@ -185,6 +199,7 @@
 
         // Captures data for token3 call.
         LooperStats.ExportedEntry entry3 = entries.get(2);
+        assertThat(entry3.workSourceUid).isEqualTo(-1);
         assertThat(entry3.threadName).isEqualTo("TestThread2");
         assertThat(entry3.handlerClassName).isEqualTo(
                 "com.android.internal.os.LooperStatsTest$TestHandlerSecond");
@@ -265,7 +280,7 @@
 
     @Test
     public void testMessagesOverSizeCap() {
-        TestableLooperStats looperStats = new TestableLooperStats(2, 1 /* sizeCap */);
+        TestableLooperStats looperStats = new TestableLooperStats(1, 1 /* sizeCap */);
 
         Object token1 = looperStats.messageDispatchStarting();
         looperStats.tickRealtime(100);
@@ -296,12 +311,12 @@
         assertThat(entry1.handlerClassName).isEqualTo("");
         assertThat(entry1.messageName).isEqualTo("OVERFLOW");
         assertThat(entry1.messageCount).isEqualTo(3);
-        assertThat(entry1.recordedMessageCount).isEqualTo(1);
+        assertThat(entry1.recordedMessageCount).isEqualTo(3);
         assertThat(entry1.exceptionCount).isEqualTo(0);
-        assertThat(entry1.totalLatencyMicros).isEqualTo(10);
-        assertThat(entry1.maxLatencyMicros).isEqualTo(10);
-        assertThat(entry1.cpuUsageMicros).isEqualTo(10);
-        assertThat(entry1.maxCpuUsageMicros).isEqualTo(10);
+        assertThat(entry1.totalLatencyMicros).isEqualTo(70);
+        assertThat(entry1.maxLatencyMicros).isEqualTo(50);
+        assertThat(entry1.cpuUsageMicros).isEqualTo(40);
+        assertThat(entry1.maxCpuUsageMicros).isEqualTo(20);
 
         LooperStats.ExportedEntry entry2 = entries.get(1);
         assertThat(entry2.threadName).isEqualTo("TestThread1");
@@ -342,6 +357,20 @@
         assertThat(looperStats.getEntries().get(0).messageCount).isEqualTo(2);
     }
 
+    @Test
+    public void testReset() {
+        TestableLooperStats looperStats = new TestableLooperStats(1, 1);
+
+        Object token1 = looperStats.messageDispatchStarting();
+        looperStats.messageDispatched(token1, mHandlerFirst.obtainMessage(1000));
+        Object token2 = looperStats.messageDispatchStarting();
+        looperStats.messageDispatched(token2, mHandlerFirst.obtainMessage(2000));
+        looperStats.reset();
+
+        List<LooperStats.ExportedEntry> entries = looperStats.getEntries();
+        assertThat(entries).hasSize(0);
+    }
+
     private static void assertThrows(Class<? extends Exception> exceptionClass, Runnable r) {
         try {
             r.run();
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 6f52fbd..73c10d2 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -188,6 +188,12 @@
     <library name="android.test.runner"
             file="/system/framework/android.test.runner.impl.jar" />
 
+    <!-- In BOOT_JARS historically, and now added to legacy applications. -->
+    <library name="android.hidl.base-V1.0-java"
+            file="/system/framework/android.hidl.base-V1.0-java.jar" />
+    <library name="android.hidl.manager-V1.0-java"
+            file="/system/framework/android.hidl.manager-V1.0-java.jar" />
+
     <!-- These are the standard packages that are white-listed to always have internet
          access while in power save mode, even if they aren't in the foreground. -->
     <allow-in-power-save package="com.android.providers.downloads" />
@@ -204,6 +210,11 @@
     <allow-in-power-save-except-idle package="com.android.providers.calendar" />
     <allow-in-power-save-except-idle package="com.android.providers.contacts" />
 
+    <!-- The PAC proxy process must have network access, otherwise no app will
+         be able to connect to the internet when such a proxy is in use, since
+         all outgoing connections originate from this app. -->
+    <allow-in-power-save-except-idle package="com.android.proxyhandler" />
+
     <!-- These are the packages that are white-listed to be able to run as system user -->
     <system-user-whitelisted-app package="com.android.settings" />
 
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 616a8d6..114c228 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -281,6 +281,7 @@
         <permission name="android.permission.MANAGE_FINGERPRINT"/>
         <permission name="android.permission.MODIFY_PHONE_STATE"/>
         <permission name="android.permission.READ_SEARCH_INDEXABLES"/>
+        <permission name="android.permission.WRITE_SETTINGS_HOMEPAGE_DATA"/>
     </privapp-permissions>
 
     <privapp-permissions package="com.android.sharedstoragebackup">
diff --git a/data/keyboards/Vendor_054c_Product_0268.kl b/data/keyboards/Vendor_054c_Product_0268.kl
index 522db3c..b463dd8 100644
--- a/data/keyboards/Vendor_054c_Product_0268.kl
+++ b/data/keyboards/Vendor_054c_Product_0268.kl
@@ -21,8 +21,6 @@
 key 0x126    DPAD_DOWN
 key 0x127    DPAD_LEFT
 
-key 0x120    BUTTON_SELECT
-key 0x123    BUTTON_START
 key 0x12e    BUTTON_A
 key 0x12d    BUTTON_B
 key 0x12f    BUTTON_X
@@ -34,9 +32,6 @@
 key 0x121    BUTTON_THUMBL
 key 0x122    BUTTON_THUMBR
 
-# PS key
-key 0x2d0    BUTTON_MODE
-
 # Left Analog Stick
 axis 0x00    X
 axis 0x01    Y
@@ -74,3 +69,11 @@
 
 # Square
 # axis 0x37
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Select
+key 0x120    BUTTON_SELECT
+# Start
+key 0x123    BUTTON_START
+# PS key
+key 0x2d0    BUTTON_MODE
diff --git a/data/keyboards/Vendor_054c_Product_0268_Version_8000.kl b/data/keyboards/Vendor_054c_Product_0268_Version_8000.kl
new file mode 100644
index 0000000..3d93f0f
--- /dev/null
+++ b/data/keyboards/Vendor_054c_Product_0268_Version_8000.kl
@@ -0,0 +1,57 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Sony Playstation(R)3 Controller
+# - Version 0x8000 and 0x8100 are for Linux hid-sony driver >=4.12
+#   and when connected over Bluetooth
+#
+
+key 0x220   DPAD_UP
+key 0x223   DPAD_RIGHT
+key 0x221   DPAD_DOWN
+key 0x222   DPAD_LEFT
+
+key 0x130   BUTTON_A
+key 0x131   BUTTON_B
+key 0x134   BUTTON_X
+key 0x133   BUTTON_Y
+key 0x136   BUTTON_L1
+key 0x137   BUTTON_R1
+key 0x138   BUTTON_L2
+key 0x139   BUTTON_R2
+key 0x13d   BUTTON_THUMBL
+key 0x13e   BUTTON_THUMBR
+
+# left Analog Stick
+axis 0x00   X
+axis 0x01   Y
+
+# Right Analog Stick
+axis 0x03   Z
+axis 0x04   RZ
+
+# L2 trigger
+axis 0x02   LTRIGGER
+
+# R2 trigger
+axis 0x05   RTRIGGER
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Select
+key 0x13a   BUTTON_SELECT
+# Start
+key 0x13b   BUTTON_START
+# PS key
+key 0x13c   BUTTON_MODE
diff --git a/data/keyboards/Vendor_054c_Product_0268_Version_8100.kl b/data/keyboards/Vendor_054c_Product_0268_Version_8100.kl
new file mode 100644
index 0000000..3d93f0f
--- /dev/null
+++ b/data/keyboards/Vendor_054c_Product_0268_Version_8100.kl
@@ -0,0 +1,57 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Sony Playstation(R)3 Controller
+# - Version 0x8000 and 0x8100 are for Linux hid-sony driver >=4.12
+#   and when connected over Bluetooth
+#
+
+key 0x220   DPAD_UP
+key 0x223   DPAD_RIGHT
+key 0x221   DPAD_DOWN
+key 0x222   DPAD_LEFT
+
+key 0x130   BUTTON_A
+key 0x131   BUTTON_B
+key 0x134   BUTTON_X
+key 0x133   BUTTON_Y
+key 0x136   BUTTON_L1
+key 0x137   BUTTON_R1
+key 0x138   BUTTON_L2
+key 0x139   BUTTON_R2
+key 0x13d   BUTTON_THUMBL
+key 0x13e   BUTTON_THUMBR
+
+# left Analog Stick
+axis 0x00   X
+axis 0x01   Y
+
+# Right Analog Stick
+axis 0x03   Z
+axis 0x04   RZ
+
+# L2 trigger
+axis 0x02   LTRIGGER
+
+# R2 trigger
+axis 0x05   RTRIGGER
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Select
+key 0x13a   BUTTON_SELECT
+# Start
+key 0x13b   BUTTON_START
+# PS key
+key 0x13c   BUTTON_MODE
diff --git a/data/keyboards/Vendor_054c_Product_0268_Version_8111.kl b/data/keyboards/Vendor_054c_Product_0268_Version_8111.kl
new file mode 100644
index 0000000..5fe35f7
--- /dev/null
+++ b/data/keyboards/Vendor_054c_Product_0268_Version_8111.kl
@@ -0,0 +1,57 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Sony Playstation(R)3 Controller
+# - Version 0x8111 is for Linux hid-sony driver >=4.12 and when
+#   connected over USB
+#
+
+key 0x220   DPAD_UP
+key 0x223   DPAD_RIGHT
+key 0x221   DPAD_DOWN
+key 0x222   DPAD_LEFT
+
+key 0x130   BUTTON_A
+key 0x131   BUTTON_B
+key 0x134   BUTTON_X
+key 0x133   BUTTON_Y
+key 0x136   BUTTON_L1
+key 0x137   BUTTON_R1
+key 0x138   BUTTON_L2
+key 0x139   BUTTON_R2
+key 0x13d   BUTTON_THUMBL
+key 0x13e   BUTTON_THUMBR
+
+# left Analog Stick
+axis 0x00   X
+axis 0x01   Y
+
+# Right Analog Stick
+axis 0x03   Z
+axis 0x04   RZ
+
+# L2 trigger
+axis 0x02   LTRIGGER
+
+# R2 trigger
+axis 0x05   RTRIGGER
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Select
+key 0x13a   BUTTON_SELECT
+# Start
+key 0x13b   BUTTON_START
+# PS key
+key 0x13c   BUTTON_MODE
diff --git a/data/keyboards/Vendor_054c_Product_05c4.kl b/data/keyboards/Vendor_054c_Product_05c4.kl
index a1284a4..cd7ab1f 100644
--- a/data/keyboards/Vendor_054c_Product_05c4.kl
+++ b/data/keyboards/Vendor_054c_Product_05c4.kl
@@ -60,7 +60,6 @@
 key 0x138    BUTTON_SELECT
 # Options
 key 0x139    BUTTON_START
-
 # PS key
 key 0x13c    BUTTON_MODE
 
diff --git a/data/keyboards/Vendor_054c_Product_05c4_Version_8000.kl b/data/keyboards/Vendor_054c_Product_05c4_Version_8000.kl
new file mode 100644
index 0000000..19fcb86
--- /dev/null
+++ b/data/keyboards/Vendor_054c_Product_05c4_Version_8000.kl
@@ -0,0 +1,68 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Sony Playstation(R) DualShock 4 Controller
+# - Version 0x8000 and 0x8100 are for Linux hid-sony driver >=4.10
+#   and when connected over Bluetooth
+#
+
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+# Square
+key 0x134   BUTTON_X
+# Cross
+key 0x130   BUTTON_A
+# Circle
+key 0x131   BUTTON_B
+# Triangle
+key 0x133   BUTTON_Y
+
+key 0x136   BUTTON_L1
+key 0x137   BUTTON_R1
+key 0x138   BUTTON_L2
+key 0x139   BUTTON_R2
+
+# L2 axis
+axis 0x02   LTRIGGER
+# R2 axis
+axis 0x05   RTRIGGER
+
+# Left Analog Stick
+axis 0x00   X
+axis 0x01   Y
+# Right Analog Stick
+axis 0x03   Z
+axis 0x04   RZ
+
+# Left stick click
+key 0x13d   BUTTON_THUMBL
+# Right stick click
+key 0x13e   BUTTON_THUMBR
+
+# Hat
+axis 0x10   HAT_X
+axis 0x11   HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Share
+key 0x13a   BUTTON_SELECT
+# Options
+key 0x13b   BUTTON_START
+# PS key
+key 0x13c   BUTTON_MODE
+
+# In kernel versions >= 4.10, the touchpad is a separate input device,
+# so the touchpad button click will not be covered by this layout.
diff --git a/data/keyboards/Vendor_054c_Product_05c4_Version_8100.kl b/data/keyboards/Vendor_054c_Product_05c4_Version_8100.kl
new file mode 100644
index 0000000..19fcb86
--- /dev/null
+++ b/data/keyboards/Vendor_054c_Product_05c4_Version_8100.kl
@@ -0,0 +1,68 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Sony Playstation(R) DualShock 4 Controller
+# - Version 0x8000 and 0x8100 are for Linux hid-sony driver >=4.10
+#   and when connected over Bluetooth
+#
+
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+# Square
+key 0x134   BUTTON_X
+# Cross
+key 0x130   BUTTON_A
+# Circle
+key 0x131   BUTTON_B
+# Triangle
+key 0x133   BUTTON_Y
+
+key 0x136   BUTTON_L1
+key 0x137   BUTTON_R1
+key 0x138   BUTTON_L2
+key 0x139   BUTTON_R2
+
+# L2 axis
+axis 0x02   LTRIGGER
+# R2 axis
+axis 0x05   RTRIGGER
+
+# Left Analog Stick
+axis 0x00   X
+axis 0x01   Y
+# Right Analog Stick
+axis 0x03   Z
+axis 0x04   RZ
+
+# Left stick click
+key 0x13d   BUTTON_THUMBL
+# Right stick click
+key 0x13e   BUTTON_THUMBR
+
+# Hat
+axis 0x10   HAT_X
+axis 0x11   HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Share
+key 0x13a   BUTTON_SELECT
+# Options
+key 0x13b   BUTTON_START
+# PS key
+key 0x13c   BUTTON_MODE
+
+# In kernel versions >= 4.10, the touchpad is a separate input device,
+# so the touchpad button click will not be covered by this layout.
diff --git a/data/keyboards/Vendor_054c_Product_05c4_Version_8111.kl b/data/keyboards/Vendor_054c_Product_05c4_Version_8111.kl
new file mode 100644
index 0000000..d38bdec
--- /dev/null
+++ b/data/keyboards/Vendor_054c_Product_05c4_Version_8111.kl
@@ -0,0 +1,68 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Sony Playstation(R) DualShock 4 Controller
+# - Version 0x8111 is for Linux hid-sony driver >=4.10 and when
+#   connected over USB
+#
+
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+# Square
+key 0x134   BUTTON_X
+# Cross
+key 0x130   BUTTON_A
+# Circle
+key 0x131   BUTTON_B
+# Triangle
+key 0x133   BUTTON_Y
+
+key 0x136   BUTTON_L1
+key 0x137   BUTTON_R1
+key 0x138   BUTTON_L2
+key 0x139   BUTTON_R2
+
+# L2 axis
+axis 0x02   LTRIGGER
+# R2 axis
+axis 0x05   RTRIGGER
+
+# Left Analog Stick
+axis 0x00   X
+axis 0x01   Y
+# Right Analog Stick
+axis 0x03   Z
+axis 0x04   RZ
+
+# Left stick click
+key 0x13d   BUTTON_THUMBL
+# Right stick click
+key 0x13e   BUTTON_THUMBR
+
+# Hat
+axis 0x10   HAT_X
+axis 0x11   HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Share
+key 0x13a   BUTTON_SELECT
+# Options
+key 0x13b   BUTTON_START
+# PS key
+key 0x13c   BUTTON_MODE
+
+# In kernel versions >= 4.10, the touchpad is a separate input device,
+# so the touchpad button click will not be covered by this layout.
diff --git a/data/keyboards/Vendor_054c_Product_09cc.kl b/data/keyboards/Vendor_054c_Product_09cc.kl
index a1284a4..cd7ab1f 100644
--- a/data/keyboards/Vendor_054c_Product_09cc.kl
+++ b/data/keyboards/Vendor_054c_Product_09cc.kl
@@ -60,7 +60,6 @@
 key 0x138    BUTTON_SELECT
 # Options
 key 0x139    BUTTON_START
-
 # PS key
 key 0x13c    BUTTON_MODE
 
diff --git a/data/keyboards/Vendor_054c_Product_09cc_Version_8000.kl b/data/keyboards/Vendor_054c_Product_09cc_Version_8000.kl
new file mode 100644
index 0000000..19fcb86
--- /dev/null
+++ b/data/keyboards/Vendor_054c_Product_09cc_Version_8000.kl
@@ -0,0 +1,68 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Sony Playstation(R) DualShock 4 Controller
+# - Version 0x8000 and 0x8100 are for Linux hid-sony driver >=4.10
+#   and when connected over Bluetooth
+#
+
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+# Square
+key 0x134   BUTTON_X
+# Cross
+key 0x130   BUTTON_A
+# Circle
+key 0x131   BUTTON_B
+# Triangle
+key 0x133   BUTTON_Y
+
+key 0x136   BUTTON_L1
+key 0x137   BUTTON_R1
+key 0x138   BUTTON_L2
+key 0x139   BUTTON_R2
+
+# L2 axis
+axis 0x02   LTRIGGER
+# R2 axis
+axis 0x05   RTRIGGER
+
+# Left Analog Stick
+axis 0x00   X
+axis 0x01   Y
+# Right Analog Stick
+axis 0x03   Z
+axis 0x04   RZ
+
+# Left stick click
+key 0x13d   BUTTON_THUMBL
+# Right stick click
+key 0x13e   BUTTON_THUMBR
+
+# Hat
+axis 0x10   HAT_X
+axis 0x11   HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Share
+key 0x13a   BUTTON_SELECT
+# Options
+key 0x13b   BUTTON_START
+# PS key
+key 0x13c   BUTTON_MODE
+
+# In kernel versions >= 4.10, the touchpad is a separate input device,
+# so the touchpad button click will not be covered by this layout.
diff --git a/data/keyboards/Vendor_054c_Product_09cc_Version_8100.kl b/data/keyboards/Vendor_054c_Product_09cc_Version_8100.kl
new file mode 100644
index 0000000..19fcb86
--- /dev/null
+++ b/data/keyboards/Vendor_054c_Product_09cc_Version_8100.kl
@@ -0,0 +1,68 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Sony Playstation(R) DualShock 4 Controller
+# - Version 0x8000 and 0x8100 are for Linux hid-sony driver >=4.10
+#   and when connected over Bluetooth
+#
+
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+# Square
+key 0x134   BUTTON_X
+# Cross
+key 0x130   BUTTON_A
+# Circle
+key 0x131   BUTTON_B
+# Triangle
+key 0x133   BUTTON_Y
+
+key 0x136   BUTTON_L1
+key 0x137   BUTTON_R1
+key 0x138   BUTTON_L2
+key 0x139   BUTTON_R2
+
+# L2 axis
+axis 0x02   LTRIGGER
+# R2 axis
+axis 0x05   RTRIGGER
+
+# Left Analog Stick
+axis 0x00   X
+axis 0x01   Y
+# Right Analog Stick
+axis 0x03   Z
+axis 0x04   RZ
+
+# Left stick click
+key 0x13d   BUTTON_THUMBL
+# Right stick click
+key 0x13e   BUTTON_THUMBR
+
+# Hat
+axis 0x10   HAT_X
+axis 0x11   HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Share
+key 0x13a   BUTTON_SELECT
+# Options
+key 0x13b   BUTTON_START
+# PS key
+key 0x13c   BUTTON_MODE
+
+# In kernel versions >= 4.10, the touchpad is a separate input device,
+# so the touchpad button click will not be covered by this layout.
diff --git a/data/keyboards/Vendor_054c_Product_09cc_Version_8111.kl b/data/keyboards/Vendor_054c_Product_09cc_Version_8111.kl
new file mode 100644
index 0000000..d38bdec
--- /dev/null
+++ b/data/keyboards/Vendor_054c_Product_09cc_Version_8111.kl
@@ -0,0 +1,68 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Sony Playstation(R) DualShock 4 Controller
+# - Version 0x8111 is for Linux hid-sony driver >=4.10 and when
+#   connected over USB
+#
+
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+# Square
+key 0x134   BUTTON_X
+# Cross
+key 0x130   BUTTON_A
+# Circle
+key 0x131   BUTTON_B
+# Triangle
+key 0x133   BUTTON_Y
+
+key 0x136   BUTTON_L1
+key 0x137   BUTTON_R1
+key 0x138   BUTTON_L2
+key 0x139   BUTTON_R2
+
+# L2 axis
+axis 0x02   LTRIGGER
+# R2 axis
+axis 0x05   RTRIGGER
+
+# Left Analog Stick
+axis 0x00   X
+axis 0x01   Y
+# Right Analog Stick
+axis 0x03   Z
+axis 0x04   RZ
+
+# Left stick click
+key 0x13d   BUTTON_THUMBL
+# Right stick click
+key 0x13e   BUTTON_THUMBR
+
+# Hat
+axis 0x10   HAT_X
+axis 0x11   HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Share
+key 0x13a   BUTTON_SELECT
+# Options
+key 0x13b   BUTTON_START
+# PS key
+key 0x13c   BUTTON_MODE
+
+# In kernel versions >= 4.10, the touchpad is a separate input device,
+# so the touchpad button click will not be covered by this layout.
diff --git a/data/keyboards/Vendor_054c_Product_0ba0.kl b/data/keyboards/Vendor_054c_Product_0ba0.kl
new file mode 100644
index 0000000..bc6fc3b
--- /dev/null
+++ b/data/keyboards/Vendor_054c_Product_0ba0.kl
@@ -0,0 +1,70 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Sony Playstation(R) DualShock 4 USB Dongle
+#
+
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+# Square
+key 0x130    BUTTON_X
+# Cross
+key 0x131    BUTTON_A
+# Circle
+key 0x132    BUTTON_B
+# Triangle
+key 0x133    BUTTON_Y
+
+key 0x134    BUTTON_L1
+key 0x135    BUTTON_R1
+key 0x136    BUTTON_L2
+key 0x137    BUTTON_R2
+
+# L2 axis
+axis 0x03   LTRIGGER
+# R2 axis
+axis 0x04   RTRIGGER
+
+
+# Left Analog Stick
+axis 0x00    X
+axis 0x01    Y
+# Right Analog Stick
+axis 0x02    Z
+axis 0x05    RZ
+
+# Left stick click
+key 0x13a    BUTTON_THUMBL
+# Right stick click
+key 0x13b    BUTTON_THUMBR
+
+# Hat
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Share
+key 0x138    BUTTON_SELECT
+# Options
+key 0x139    BUTTON_START
+# PS key
+key 0x13c    BUTTON_MODE
+
+# Touchpad press
+# The touchpad for this joystick will become a separate input device in future releases
+# and this button will be equivalent to left mouse button
+# Therefore, map it to KEYCODE_BUTTON_1 here to allow apps to still handle this on earlier versions
+key 0x13d   BUTTON_1
diff --git a/data/keyboards/Vendor_054c_Product_0ba0_Version_8111.kl b/data/keyboards/Vendor_054c_Product_0ba0_Version_8111.kl
new file mode 100644
index 0000000..8b85a38
--- /dev/null
+++ b/data/keyboards/Vendor_054c_Product_0ba0_Version_8111.kl
@@ -0,0 +1,67 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Sony Playstation(R) DualShock 4 USB Dongle
+# - Version 0x8111 is for Linux hid-sony driver >=4.10
+#
+
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+# Square
+key 0x134   BUTTON_X
+# Cross
+key 0x130   BUTTON_A
+# Circle
+key 0x131   BUTTON_B
+# Triangle
+key 0x133   BUTTON_Y
+
+key 0x136   BUTTON_L1
+key 0x137   BUTTON_R1
+key 0x138   BUTTON_L2
+key 0x139   BUTTON_R2
+
+# L2 axis
+axis 0x02   LTRIGGER
+# R2 axis
+axis 0x05   RTRIGGER
+
+# Left Analog Stick
+axis 0x00   X
+axis 0x01   Y
+# Right Analog Stick
+axis 0x03   Z
+axis 0x04   RZ
+
+# Left stick click
+key 0x13d   BUTTON_THUMBL
+# Right stick click
+key 0x13e   BUTTON_THUMBR
+
+# Hat
+axis 0x10   HAT_X
+axis 0x11   HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Share
+key 0x13a   BUTTON_SELECT
+# Options
+key 0x13b   BUTTON_START
+# PS key
+key 0x13c   BUTTON_MODE
+
+# In kernel versions >= 4.10, the touchpad is a separate input device,
+# so the touchpad button click will not be covered by this layout.
diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java
index 53e9826..fa37bed 100644
--- a/graphics/java/android/graphics/BaseCanvas.java
+++ b/graphics/java/android/graphics/BaseCanvas.java
@@ -28,11 +28,10 @@
 import android.text.SpannableString;
 import android.text.SpannedString;
 import android.text.TextUtils;
-import android.view.RecordingCanvas;
 
 /**
  * This class is a base class for Canvas's drawing operations. Any modifications here
- * should be accompanied by a similar modification to {@link RecordingCanvas}.
+ * should be accompanied by a similar modification to {@link BaseRecordingCanvas}.
  *
  * The purpose of this class is to minimize the cost of deciding between regular JNI
  * and @FastNative JNI to just the virtual call that Canvas already has.
diff --git a/core/java/android/view/RecordingCanvas.java b/graphics/java/android/graphics/BaseRecordingCanvas.java
similarity index 97%
rename from core/java/android/view/RecordingCanvas.java
rename to graphics/java/android/graphics/BaseRecordingCanvas.java
index 3364483..6e93691 100644
--- a/core/java/android/view/RecordingCanvas.java
+++ b/graphics/java/android/graphics/BaseRecordingCanvas.java
@@ -14,25 +14,12 @@
  * limitations under the License.
  */
 
-package android.view;
+package android.graphics;
 
 import android.annotation.ColorInt;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.Size;
-import android.graphics.BaseCanvas;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Matrix;
-import android.graphics.NinePatch;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.Picture;
-import android.graphics.PorterDuff;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.TemporaryBuffer;
 import android.text.GraphicsOperations;
 import android.text.MeasuredParagraph;
 import android.text.PrecomputedText;
@@ -49,9 +36,9 @@
  *
  * @hide
  */
-public class RecordingCanvas extends Canvas {
+public class BaseRecordingCanvas extends Canvas {
 
-    public RecordingCanvas(long nativeCanvas) {
+    public BaseRecordingCanvas(long nativeCanvas) {
         super(nativeCanvas);
     }
 
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index cea6c1c..9cbbf4e 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -1253,6 +1253,7 @@
             final RenderNode node = RenderNode.create("BitmapTemporary", null);
             node.setLeftTopRightBottom(0, 0, width, height);
             node.setClipToBounds(false);
+            node.setAllowForceDark(false);
             final DisplayListCanvas canvas = node.start(width, height);
             if (source.getWidth() != width || source.getHeight() != height) {
                 canvas.scale(width / (float) source.getWidth(),
diff --git a/graphics/java/android/graphics/BitmapRegionDecoder.java b/graphics/java/android/graphics/BitmapRegionDecoder.java
index 9b5027d..43282d3 100644
--- a/graphics/java/android/graphics/BitmapRegionDecoder.java
+++ b/graphics/java/android/graphics/BitmapRegionDecoder.java
@@ -17,6 +17,7 @@
 
 import android.annotation.UnsupportedAppUsage;
 import android.content.res.AssetManager;
+import android.os.Build;
 
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
@@ -166,7 +167,7 @@
 
         This can be called from JNI code.
     */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private BitmapRegionDecoder(long decoder) {
         mNativeBitmapRegionDecoder = decoder;
         mRecycled = false;
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index ef58c8f..36c1c21 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -126,7 +126,7 @@
     }
 
     /** @hide */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public Canvas(long nativeCanvas) {
         if (nativeCanvas == 0) {
             throw new IllegalStateException();
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 7bed1ac..6ce66bd 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -187,7 +187,7 @@
      *  {@link OnHeaderDecodedListener OnHeaderDecodedListener} and once with an
      *  implementation of {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}
      *  that calls {@link #setTargetSize} with smaller dimensions. One {@code Source}
-     *  even used simultaneously in multiple threads.</p>
+     *  can even be used simultaneously in multiple threads.</p>
      */
     public static abstract class Source {
         private Source() {}
diff --git a/graphics/java/android/graphics/Movie.java b/graphics/java/android/graphics/Movie.java
index 8162544..6f030ff 100644
--- a/graphics/java/android/graphics/Movie.java
+++ b/graphics/java/android/graphics/Movie.java
@@ -18,6 +18,7 @@
 
 import android.annotation.UnsupportedAppUsage;
 import android.content.res.AssetManager;
+import android.os.Build;
 
 import java.io.FileInputStream;
 import java.io.InputStream;
@@ -30,7 +31,7 @@
     @UnsupportedAppUsage
     private long mNativeMovie;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private Movie(long nativeMovie) {
         if (nativeMovie == 0) {
             throw new RuntimeException("native movie creation failed");
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 6f30653..69ff3bc 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -17,7 +17,10 @@
 package android.graphics;
 
 import android.annotation.ColorInt;
+import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.Px;
 import android.annotation.Size;
 import android.annotation.UnsupportedAppUsage;
@@ -35,6 +38,8 @@
 
 import libcore.util.NativeAllocationRegistry;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -307,38 +312,47 @@
      */
     public static final int DIRECTION_RTL = 1;
 
+    /** @hide */
+    @IntDef(prefix = { "CURSOR_" }, value = {
+        CURSOR_AFTER, CURSOR_AT_OR_AFTER, CURSOR_BEFORE, CURSOR_AT_OR_BEFORE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CursorOption {}
+
     /**
-     * Option for getTextRunCursor to compute the valid cursor after
-     * offset or the limit of the context, whichever is less.
-     * @hide
+     * Option for getTextRunCursor.
+     *
+     * Compute the valid cursor after offset or the limit of the context, whichever is less.
      */
     public static final int CURSOR_AFTER = 0;
 
     /**
-     * Option for getTextRunCursor to compute the valid cursor at or after
-     * the offset or the limit of the context, whichever is less.
-     * @hide
+     * Option for getTextRunCursor.
+     *
+     * Compute the valid cursor at or after the offset or the limit of the context, whichever is
+     * less.
      */
     public static final int CURSOR_AT_OR_AFTER = 1;
 
      /**
-     * Option for getTextRunCursor to compute the valid cursor before
-     * offset or the start of the context, whichever is greater.
-     * @hide
+     * Option for getTextRunCursor.
+     *
+     * Compute the valid cursor before offset or the start of the context, whichever is greater.
      */
     public static final int CURSOR_BEFORE = 2;
 
    /**
-     * Option for getTextRunCursor to compute the valid cursor at or before
-     * offset or the start of the context, whichever is greater.
-     * @hide
+     * Option for getTextRunCursor.
+     *
+     * Compute the valid cursor at or before offset or the start of the context, whichever is
+     * greater.
      */
     public static final int CURSOR_AT_OR_BEFORE = 3;
 
     /**
-     * Option for getTextRunCursor to return offset if the cursor at offset
-     * is valid, or -1 if it isn't.
-     * @hide
+     * Option for getTextRunCursor.
+     *
+     * Return offset if the cursor at offset is valid, or -1 if it isn't.
      */
     public static final int CURSOR_AT = 4;
 
@@ -578,49 +592,6 @@
         mShadowLayerColor = paint.mShadowLayerColor;
     }
 
-    /**
-     * Returns true if all attributes are equal.
-     *
-     * The caller is expected to have checked the trivial cases, like the pointers being equal,
-     * the objects having different classes, or the parameter being null.
-     * @hide
-     */
-    public boolean hasEqualAttributes(@NonNull Paint other) {
-        return mColorFilter == other.mColorFilter
-                && mMaskFilter == other.mMaskFilter
-                && mPathEffect == other.mPathEffect
-                && mShader == other.mShader
-                && mTypeface == other.mTypeface
-                && mXfermode == other.mXfermode
-                && mHasCompatScaling == other.mHasCompatScaling
-                && mCompatScaling == other.mCompatScaling
-                && mInvCompatScaling == other.mInvCompatScaling
-                && mBidiFlags == other.mBidiFlags
-                && mLocales.equals(other.mLocales)
-                && TextUtils.equals(mFontFeatureSettings, other.mFontFeatureSettings)
-                && TextUtils.equals(mFontVariationSettings, other.mFontVariationSettings)
-                && mShadowLayerRadius == other.mShadowLayerRadius
-                && mShadowLayerDx == other.mShadowLayerDx
-                && mShadowLayerDy == other.mShadowLayerDy
-                && mShadowLayerColor == other.mShadowLayerColor
-                && getFlags() == other.getFlags()
-                && getHinting() == other.getHinting()
-                && getStyle() == other.getStyle()
-                && getColor() == other.getColor()
-                && getStrokeWidth() == other.getStrokeWidth()
-                && getStrokeMiter() == other.getStrokeMiter()
-                && getStrokeCap() == other.getStrokeCap()
-                && getStrokeJoin() == other.getStrokeJoin()
-                && getTextAlign() == other.getTextAlign()
-                && isElegantTextHeight() == other.isElegantTextHeight()
-                && getTextSize() == other.getTextSize()
-                && getTextScaleX() == other.getTextScaleX()
-                && getTextSkewX() == other.getTextSkewX()
-                && getLetterSpacing() == other.getLetterSpacing()
-                && getWordSpacing() == other.getWordSpacing()
-                && getHyphenEdit() == other.getHyphenEdit();
-    }
-
     /** @hide */
     @UnsupportedAppUsage
     public void setCompatibilityScaling(float factor) {
@@ -1381,6 +1352,38 @@
     }
 
     /**
+     * Returns the blur radius of the shadow layer.
+     * @see #setShadowLayer(float,float,float,int)
+     */
+    public float getShadowLayerRadius() {
+        return mShadowLayerRadius;
+    }
+
+    /**
+     * Returns the x offset of the shadow layer.
+     * @see #setShadowLayer(float,float,float,int)
+     */
+    public float getShadowLayerDx() {
+        return mShadowLayerDx;
+    }
+
+    /**
+     * Returns the y offset of the shadow layer.
+     * @see #setShadowLayer(float,float,float,int)
+     */
+    public float getShadowLayerDy() {
+        return mShadowLayerDy;
+    }
+
+    /**
+     * Returns the color of the shadow layer.
+     * @see #setShadowLayer(float,float,float,int)
+     */
+    public @ColorInt int getShadowLayerColor() {
+        return mShadowLayerColor;
+    }
+
+    /**
      * Return the paint's Align value for drawing text. This controls how the
      * text is positioned relative to its origin. LEFT align means that all of
      * the text will be drawn to the right of its origin (i.e. the origin
@@ -2325,17 +2328,53 @@
     }
 
     /**
-     * Convenience overload that takes a char array instead of a
-     * String.
+     * Retrieve the character advances of the text.
      *
-     * @see #getTextRunAdvances(String, int, int, int, int, boolean, float[], int)
-     * @hide
+     * Returns the total advance width for the characters in the run from {@code index} for
+     * {@code count} of chars, and if {@code advances} is not null, the advance assigned to each of
+     * these characters (java chars).
+     *
+     * <p>
+     * The trailing surrogate in a valid surrogate pair is assigned an advance of 0.  Thus the
+     * number of returned advances is always equal to count, not to the number of unicode codepoints
+     * represented by the run.
+     * </p>
+     *
+     * <p>
+     * In the case of conjuncts or combining marks, the total advance is assigned to the first
+     * logical character, and the following characters are assigned an advance of 0.
+     * </p>
+     *
+     * <p>
+     * This generates the sum of the advances of glyphs for characters in a reordered cluster as the
+     * width of the first logical character in the cluster, and 0 for the widths of all other
+     * characters in the cluster.  In effect, such clusters are treated like conjuncts.
+     * </p>
+     *
+     * <p>
+     * The shaping bounds limit the amount of context available outside start and end that can be
+     * used for shaping analysis.  These bounds typically reflect changes in bidi level or font
+     * metrics across which shaping does not occur.
+     * </p>
+     *
+     * @param chars the text to measure.
+     * @param index the index of the first character to measure
+     * @param count the number of characters to measure
+     * @param contextIndex the index of the first character to use for shaping context.
+     *                     Context must cover the measureing target.
+     * @param contextCount the number of character to use for shaping context.
+     *                     Context must cover the measureing target.
+     * @param isRtl whether the run is in RTL direction
+     * @param advances array to receive the advances, must have room for all advances.
+     *                 This can be null if only total advance is needed
+     * @param advancesIndex the position in advances at which to put the advance corresponding to
+     *                      the character at start
+     * @return the total advance in pixels
      */
-    @UnsupportedAppUsage
-    public float getTextRunAdvances(char[] chars, int index, int count,
-            int contextIndex, int contextCount, boolean isRtl, float[] advances,
-            int advancesIndex) {
-
+    public float getTextRunAdvances(@NonNull char[] chars, @IntRange(from = 0) int index,
+            @IntRange(from = 0) int count, @IntRange(from = 0) int contextIndex,
+            @IntRange(from = 0) int contextCount, boolean isRtl, @Nullable float[] advances,
+            @IntRange(from = 0) int advancesIndex) {
         if (chars == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -2372,159 +2411,32 @@
     }
 
     /**
-     * Convenience overload that takes a CharSequence instead of a
-     * String.
+     * Returns the next cursor position in the run.
      *
-     * @see #getTextRunAdvances(String, int, int, int, int, boolean, float[], int)
-     * @hide
-     */
-    public float getTextRunAdvances(CharSequence text, int start, int end,
-            int contextStart, int contextEnd, boolean isRtl, float[] advances,
-            int advancesIndex) {
-        if (text == null) {
-            throw new IllegalArgumentException("text cannot be null");
-        }
-        if ((start | end | contextStart | contextEnd | advancesIndex | (end - start)
-                | (start - contextStart) | (contextEnd - end)
-                | (text.length() - contextEnd)
-                | (advances == null ? 0 :
-                    (advances.length - advancesIndex - (end - start)))) < 0) {
-            throw new IndexOutOfBoundsException();
-        }
-
-        if (text instanceof String) {
-            return getTextRunAdvances((String) text, start, end,
-                    contextStart, contextEnd, isRtl, advances, advancesIndex);
-        }
-        if (text instanceof SpannedString ||
-            text instanceof SpannableString) {
-            return getTextRunAdvances(text.toString(), start, end,
-                    contextStart, contextEnd, isRtl, advances, advancesIndex);
-        }
-        if (text instanceof GraphicsOperations) {
-            return ((GraphicsOperations) text).getTextRunAdvances(start, end,
-                    contextStart, contextEnd, isRtl, advances, advancesIndex, this);
-        }
-        if (text.length() == 0 || end == start) {
-            return 0f;
-        }
-
-        int contextLen = contextEnd - contextStart;
-        int len = end - start;
-        char[] buf = TemporaryBuffer.obtain(contextLen);
-        TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
-        float result = getTextRunAdvances(buf, start - contextStart, len,
-                0, contextLen, isRtl, advances, advancesIndex);
-        TemporaryBuffer.recycle(buf);
-        return result;
-    }
-
-    /**
-     * Returns the total advance width for the characters in the run
-     * between start and end, and if advances is not null, the advance
-     * assigned to each of these characters (java chars).
+     * This avoids placing the cursor between surrogates, between characters that form conjuncts,
+     * between base characters and combining marks, or within a reordering cluster.
      *
-     * <p>The trailing surrogate in a valid surrogate pair is assigned
-     * an advance of 0.  Thus the number of returned advances is
-     * always equal to count, not to the number of unicode codepoints
-     * represented by the run.
+     * <p>
+     * ContextStart and offset are relative to the start of text.
+     * The context is the shaping context for cursor movement, generally the bounds of the metric
+     * span enclosing the cursor in the direction of movement.
      *
-     * <p>In the case of conjuncts or combining marks, the total
-     * advance is assigned to the first logical character, and the
-     * following characters are assigned an advance of 0.
-     *
-     * <p>This generates the sum of the advances of glyphs for
-     * characters in a reordered cluster as the width of the first
-     * logical character in the cluster, and 0 for the widths of all
-     * other characters in the cluster.  In effect, such clusters are
-     * treated like conjuncts.
-     *
-     * <p>The shaping bounds limit the amount of context available
-     * outside start and end that can be used for shaping analysis.
-     * These bounds typically reflect changes in bidi level or font
-     * metrics across which shaping does not occur.
-     *
-     * @param text the text to measure. Cannot be null.
-     * @param start the index of the first character to measure
-     * @param end the index past the last character to measure
-     * @param contextStart the index of the first character to use for shaping context,
-     * must be <= start
-     * @param contextEnd the index past the last character to use for shaping context,
-     * must be >= end
-     * @param isRtl whether the run is in RTL direction
-     * @param advances array to receive the advances, must have room for all advances,
-     * can be null if only total advance is needed
-     * @param advancesIndex the position in advances at which to put the
-     * advance corresponding to the character at start
-     * @return the total advance
-     *
-     * @hide
-     */
-    public float getTextRunAdvances(String text, int start, int end, int contextStart,
-            int contextEnd, boolean isRtl, float[] advances, int advancesIndex) {
-        if (text == null) {
-            throw new IllegalArgumentException("text cannot be null");
-        }
-        if ((start | end | contextStart | contextEnd | advancesIndex | (end - start)
-                | (start - contextStart) | (contextEnd - end)
-                | (text.length() - contextEnd)
-                | (advances == null ? 0 :
-                    (advances.length - advancesIndex - (end - start)))) < 0) {
-            throw new IndexOutOfBoundsException();
-        }
-
-        if (text.length() == 0 || start == end) {
-            return 0f;
-        }
-
-        if (!mHasCompatScaling) {
-            return nGetTextAdvances(mNativePaint, text, start, end, contextStart, contextEnd,
-                    isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances, advancesIndex);
-        }
-
-        final float oldSize = getTextSize();
-        setTextSize(oldSize * mCompatScaling);
-        final float totalAdvance = nGetTextAdvances(mNativePaint, text, start, end, contextStart,
-                contextEnd, isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances, advancesIndex);
-        setTextSize(oldSize);
-
-        if (advances != null) {
-            for (int i = advancesIndex, e = i + (end - start); i < e; i++) {
-                advances[i] *= mInvCompatScaling;
-            }
-        }
-        return totalAdvance * mInvCompatScaling; // assume errors are insignificant
-    }
-
-    /**
-     * Returns the next cursor position in the run.  This avoids placing the
-     * cursor between surrogates, between characters that form conjuncts,
-     * between base characters and combining marks, or within a reordering
-     * cluster.
-     *
-     * <p>ContextStart and offset are relative to the start of text.
-     * The context is the shaping context for cursor movement, generally
-     * the bounds of the metric span enclosing the cursor in the direction of
-     * movement.
-     *
-     * <p>If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid
-     * cursor position, this returns -1.  Otherwise this will never return a
-     * value before contextStart or after contextStart + contextLength.
+     * <p>
+     * If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid cursor position, this
+     * returns -1.  Otherwise this will never return a value before contextStart or after
+     * contextStart + contextLength.
      *
      * @param text the text
      * @param contextStart the start of the context
      * @param contextLength the length of the context
-     * @param dir either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
+     * @param isRtl true if the paragraph context is RTL, otherwise false
      * @param offset the cursor position to move from
-     * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
-     * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
-     * {@link #CURSOR_AT_OR_BEFORE}, or {@link #CURSOR_AT}
+     * @param cursorOpt how to move the cursor
      * @return the offset of the next position, or -1
-     * @hide
      */
-    @UnsupportedAppUsage
-    public int getTextRunCursor(char[] text, int contextStart, int contextLength,
-            int dir, int offset, int cursorOpt) {
+    public int getTextRunCursor(@NonNull char[] text, @IntRange(from = 0) int contextStart,
+            @IntRange(from = 0) int contextLength, boolean isRtl, @IntRange(from = 0) int offset,
+            @CursorOption int cursorOpt) {
         int contextEnd = contextStart + contextLength;
         if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
                 | (offset - contextStart) | (contextEnd - offset)
@@ -2533,85 +2445,87 @@
             throw new IndexOutOfBoundsException();
         }
 
-        return nGetTextRunCursor(mNativePaint, text, contextStart, contextLength, dir, offset,
-                cursorOpt);
+        return nGetTextRunCursor(mNativePaint, text, contextStart, contextLength,
+                isRtl ? DIRECTION_RTL : DIRECTION_LTR, offset, cursorOpt);
     }
 
     /**
-     * Returns the next cursor position in the run.  This avoids placing the
-     * cursor between surrogates, between characters that form conjuncts,
-     * between base characters and combining marks, or within a reordering
-     * cluster.
+     * Returns the next cursor position in the run.
      *
-     * <p>ContextStart, contextEnd, and offset are relative to the start of
+     * This avoids placing the cursor between surrogates, between characters that form conjuncts,
+     * between base characters and combining marks, or within a reordering cluster.
+     *
+     * <p>
+     * ContextStart, contextEnd, and offset are relative to the start of
      * text.  The context is the shaping context for cursor movement, generally
      * the bounds of the metric span enclosing the cursor in the direction of
      * movement.
      *
-     * <p>If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid
-     * cursor position, this returns -1.  Otherwise this will never return a
-     * value before contextStart or after contextEnd.
+     * <p>
+     * If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid cursor position, this
+     * returns -1.  Otherwise this will never return a value before contextStart or after
+     * contextEnd.
      *
      * @param text the text
      * @param contextStart the start of the context
      * @param contextEnd the end of the context
-     * @param dir either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
+     * @param isRtl true if the paragraph context is RTL, otherwise false
      * @param offset the cursor position to move from
-     * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
-     * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
-     * {@link #CURSOR_AT_OR_BEFORE}, or {@link #CURSOR_AT}
+     * @param cursorOpt how to move the cursor
      * @return the offset of the next position, or -1
-     * @hide
      */
-    public int getTextRunCursor(CharSequence text, int contextStart,
-           int contextEnd, int dir, int offset, int cursorOpt) {
+    public int getTextRunCursor(@NonNull CharSequence text, @IntRange(from = 0) int contextStart,
+            @IntRange(from = 0) int contextEnd, boolean isRtl, @IntRange(from = 0) int offset,
+            @CursorOption int cursorOpt) {
 
         if (text instanceof String || text instanceof SpannedString ||
                 text instanceof SpannableString) {
             return getTextRunCursor(text.toString(), contextStart, contextEnd,
-                    dir, offset, cursorOpt);
+                    isRtl, offset, cursorOpt);
         }
         if (text instanceof GraphicsOperations) {
             return ((GraphicsOperations) text).getTextRunCursor(
-                    contextStart, contextEnd, dir, offset, cursorOpt, this);
+                    contextStart, contextEnd, isRtl, offset, cursorOpt, this);
         }
 
         int contextLen = contextEnd - contextStart;
         char[] buf = TemporaryBuffer.obtain(contextLen);
         TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
-        int relPos = getTextRunCursor(buf, 0, contextLen, dir, offset - contextStart, cursorOpt);
+        int relPos = getTextRunCursor(buf, 0, contextLen, isRtl, offset - contextStart, cursorOpt);
         TemporaryBuffer.recycle(buf);
         return (relPos == -1) ? -1 : relPos + contextStart;
     }
 
     /**
-     * Returns the next cursor position in the run.  This avoids placing the
-     * cursor between surrogates, between characters that form conjuncts,
-     * between base characters and combining marks, or within a reordering
-     * cluster.
+     * Returns the next cursor position in the run.
      *
-     * <p>ContextStart, contextEnd, and offset are relative to the start of
-     * text.  The context is the shaping context for cursor movement, generally
-     * the bounds of the metric span enclosing the cursor in the direction of
-     * movement.
+     * This avoids placing the cursor between surrogates, between characters that form conjuncts,
+     * between base characters and combining marks, or within a reordering cluster.
      *
-     * <p>If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid
-     * cursor position, this returns -1.  Otherwise this will never return a
-     * value before contextStart or after contextEnd.
+     * <p>
+     * ContextStart, contextEnd, and offset are relative to the start of text.  The context is the
+     * shaping context for cursor movement, generally the bounds of the metric span enclosing the
+     * cursor in the direction of movement.
+     * </p>
+     *
+     * <p>
+     * If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid cursor position, this
+     * returns -1.  Otherwise this will never return a value before contextStart or after
+     * contextEnd.
+     * </p>
      *
      * @param text the text
      * @param contextStart the start of the context
      * @param contextEnd the end of the context
-     * @param dir either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
+     * @param isRtl true if the paragraph context is RTL, otherwise false.
      * @param offset the cursor position to move from
-     * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
-     * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
-     * {@link #CURSOR_AT_OR_BEFORE}, or {@link #CURSOR_AT}
+     * @param cursorOpt how to move the cursor
      * @return the offset of the next position, or -1
      * @hide
      */
-    public int getTextRunCursor(String text, int contextStart, int contextEnd,
-            int dir, int offset, int cursorOpt) {
+    public int getTextRunCursor(@NonNull String text, @IntRange(from = 0) int contextStart,
+            @IntRange(from = 0) int contextEnd, boolean isRtl, @IntRange(from = 0) int offset,
+            @CursorOption int cursorOpt) {
         if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
                 | (offset - contextStart) | (contextEnd - offset)
                 | (text.length() - contextEnd) | cursorOpt) < 0)
@@ -2619,8 +2533,8 @@
             throw new IndexOutOfBoundsException();
         }
 
-        return nGetTextRunCursor(mNativePaint, text, contextStart, contextEnd, dir, offset,
-                cursorOpt);
+        return nGetTextRunCursor(mNativePaint, text, contextStart, contextEnd,
+                isRtl ? DIRECTION_RTL : DIRECTION_LTR, offset, cursorOpt);
     }
 
     /**
@@ -2686,11 +2600,13 @@
      * Return in bounds (allocated by the caller) the smallest rectangle that
      * encloses all of the characters, with an implied origin at (0,0).
      *
+     * Note that styles are ignored even if you pass {@link android.text.Spanned} instance.
+     * Use {@link android.text.StaticLayout} for measuring bounds of {@link android.text.Spanned}.
+     *
      * @param text text to measure and return its bounds
      * @param start index of the first char in the text to measure
      * @param end 1 past the last char in the text to measure
      * @param bounds returns the unioned bounds of all the text. Must be allocated by the caller
-     * @hide
      */
     public void getTextBounds(CharSequence text, int start, int end, Rect bounds) {
         if ((start | end | (end - start) | (text.length() - end)) < 0) {
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 5aa09ce..492c236 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -30,6 +30,7 @@
 import android.graphics.fonts.FontVariationAxis;
 import android.graphics.fonts.SystemFonts;
 import android.net.Uri;
+import android.os.Build;
 import android.provider.FontRequest;
 import android.provider.FontsContract;
 import android.text.FontConfig;
@@ -1076,7 +1077,7 @@
     }
 
     // don't allow clients to call this directly
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private Typeface(long ni) {
         if (ni == 0) {
             throw new RuntimeException("native typeface cannot be made");
diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
index 00380c5..11a46c4 100644
--- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
@@ -24,6 +24,7 @@
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
+import android.os.Build;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.LongSparseLongArray;
@@ -67,7 +68,7 @@
     private static final String ELEMENT_TRANSITION = "transition";
     private static final String ELEMENT_ITEM = "item";
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private AnimatedStateListState mState;
 
     /** The currently running transition, if any. */
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 76f2cfb..6c1372f 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -51,6 +51,7 @@
 import android.util.TimeUtils;
 import android.view.Choreographer;
 import android.view.DisplayListCanvas;
+import android.view.NativeVectorDrawableAnimator;
 import android.view.RenderNode;
 import android.view.RenderNodeAnimatorSetHelper;
 import android.view.View;
@@ -1231,7 +1232,8 @@
     /**
      * @hide
      */
-    public static class VectorDrawableAnimatorRT implements VectorDrawableAnimator {
+    public static class VectorDrawableAnimatorRT implements VectorDrawableAnimator,
+            NativeVectorDrawableAnimator {
         private static final int START_ANIMATION = 1;
         private static final int REVERSE_ANIMATION = 2;
         private static final int RESET_ANIMATION = 3;
@@ -1704,6 +1706,7 @@
             }
         }
 
+        @Override
         public long getAnimatorNativePtr() {
             return mSetPtr;
         }
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index a337773..7efe522 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -34,6 +34,7 @@
 import android.graphics.PorterDuff;
 import android.net.Uri;
 import android.os.AsyncTask;
+import android.os.Build;
 import android.os.Handler;
 import android.os.Message;
 import android.os.Parcel;
@@ -101,7 +102,7 @@
 
     private static final int VERSION_STREAM_SERIALIZER = 1;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final int mType;
 
     private ColorStateList mTintList;
@@ -118,7 +119,7 @@
 
     // TYPE_RESOURCE: package name
     // TYPE_URI: uri string
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private String          mString1;
 
     // TYPE_RESOURCE: resId
@@ -174,7 +175,7 @@
      * valid compressed bitmap data is found.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public int getDataOffset() {
         if (mType != TYPE_DATA) {
             throw new IllegalStateException("called getDataOffset() on " + this);
@@ -189,7 +190,7 @@
      * bitmap data.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public byte[] getDataBytes() {
         if (mType != TYPE_DATA) {
             throw new IllegalStateException("called getDataBytes() on " + this);
@@ -203,7 +204,7 @@
      * @return The {@link android.content.res.Resources} for this {@link #TYPE_RESOURCE} Icon.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public Resources getResources() {
         if (mType != TYPE_RESOURCE) {
             throw new IllegalStateException("called getResources() on " + this);
diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java
index 8aa4845..bd1ac25 100644
--- a/graphics/java/android/graphics/fonts/Font.java
+++ b/graphics/java/android/graphics/fonts/Font.java
@@ -119,7 +119,7 @@
 
         private @Nullable ByteBuffer mBuffer;
         private @Nullable File mFile;
-        private @NonNull LocaleList mLocaleList = LocaleList.getEmptyLocaleList();
+        private @NonNull String mLocaleList = "";
         private @IntRange(from = -1, to = 1000) int mWeight = NOT_SPECIFIED;
         private @IntRange(from = -1, to = 1) int mItalic = NOT_SPECIFIED;
         private @IntRange(from = 0) int mTtcIndex = 0;
@@ -150,7 +150,7 @@
          * @hide
          */
         public Builder(@NonNull ByteBuffer buffer, @NonNull File path,
-                @NonNull LocaleList localeList) {
+                @NonNull String localeList) {
             this(buffer);
             mFile = path;
             mLocaleList = localeList;
@@ -422,9 +422,10 @@
                     nAddAxis(builderPtr, axis.getOpenTypeTagValue(), axis.getStyleValue());
                 }
             }
-            final long ptr = nBuild(builderPtr, mBuffer, mWeight, italic, mTtcIndex);
-            final Font font = new Font(ptr, mBuffer, mFile, mWeight, italic, mTtcIndex, mAxes,
-                    mLocaleList);
+            final ByteBuffer readonlyBuffer = mBuffer.asReadOnlyBuffer();
+            final long ptr = nBuild(builderPtr, readonlyBuffer, mWeight, italic, mTtcIndex);
+            final Font font = new Font(ptr, readonlyBuffer, mFile, mWeight, italic, mTtcIndex,
+                    mAxes, mLocaleList);
             sFontRegistory.registerNativeAllocation(font, ptr);
             return font;
         }
@@ -457,7 +458,7 @@
     private final boolean mItalic;
     private final @IntRange(from = 0) int mTtcIndex;
     private final @Nullable FontVariationAxis[] mAxes;
-    private final @NonNull LocaleList mLocaleList;
+    private final @NonNull String mLocaleList;
 
     /**
      * Use Builder instead
@@ -465,7 +466,7 @@
     private Font(long nativePtr, @NonNull ByteBuffer buffer, @Nullable File file,
             @IntRange(from = 0, to = 1000) int weight, boolean italic,
             @IntRange(from = 0) int ttcIndex, @Nullable FontVariationAxis[] axes,
-            @NonNull LocaleList localeList) {
+            @NonNull String localeList) {
         mBuffer = buffer;
         mFile = file;
         mWeight = weight;
@@ -477,7 +478,7 @@
     }
 
     /**
-     * Retuns a font file buffer.
+     * Returns a font file buffer.
      *
      * @return a font buffer
      */
@@ -546,7 +547,7 @@
      * @return a locale list
      */
     public @NonNull LocaleList getLocaleList() {
-        return mLocaleList;
+        return LocaleList.forLanguageTags(mLocaleList);
     }
 
     /** @hide */
@@ -580,7 +581,7 @@
             + ", italic=" + mItalic
             + ", ttcIndex=" + mTtcIndex
             + ", axes=" + FontVariationAxis.toFontVariationSettings(mAxes)
-            + ", localeList=" + mLocaleList.toLanguageTags()
+            + ", localeList=" + mLocaleList
             + ", buffer=" + mBuffer
             + "}";
     }
diff --git a/graphics/java/android/graphics/fonts/FontVariationAxis.java b/graphics/java/android/graphics/fonts/FontVariationAxis.java
index 242cbb8..bcee559 100644
--- a/graphics/java/android/graphics/fonts/FontVariationAxis.java
+++ b/graphics/java/android/graphics/fonts/FontVariationAxis.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.text.TextUtils;
 
 import java.util.ArrayList;
@@ -29,7 +30,7 @@
  * Class that holds information about single font variation axis.
  */
 public final class FontVariationAxis {
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final int mTag;
     private final String mTagString;
     @UnsupportedAppUsage
diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java
index 1c957b8..5e80749 100644
--- a/graphics/java/android/graphics/fonts/SystemFonts.java
+++ b/graphics/java/android/graphics/fonts/SystemFonts.java
@@ -19,7 +19,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.graphics.FontListParser;
-import android.os.LocaleList;
 import android.text.FontConfig;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -46,7 +45,7 @@
 /**
  * Provides the system font configurations.
  */
-public class SystemFonts {
+public final class SystemFonts {
     private static final String TAG = "SystemFonts";
     private static final String DEFAULT_FAMILY = "sans-serif";
 
@@ -54,16 +53,17 @@
 
     private static final Map<String, FontFamily[]> sSystemFallbackMap;
     private static final FontConfig.Alias[] sAliases;
-    private static final Set<Font> sAvailableFonts;
+    private static final List<Font> sAvailableFonts;
 
     /**
      * Returns all available font files in the system.
      *
-     * Note: The order of this font doesn't indicates anything.
-     * @return an array of system fonts
+     * @return a set of system fonts
      */
     public static @NonNull Set<Font> getAvailableFonts() {
-        return sAvailableFonts;
+        HashSet<Font> set = new HashSet<>();
+        set.addAll(sAvailableFonts);
+        return set;
     }
 
     /**
@@ -114,7 +114,7 @@
             @NonNull ArrayMap<String, ArrayList<FontFamily>> fallbackMap,
             @NonNull Map<String, ByteBuffer> cache,
             @NonNull String fontDir,
-            @NonNull HashSet<Font> availableFonts) {
+            @NonNull ArrayList<Font> availableFonts) {
 
         final String languageTags = xmlFamily.getLanguages();
         final int variant = xmlFamily.getVariant();
@@ -170,13 +170,12 @@
             @FontConfig.Family.Variant int variant,
             @NonNull Map<String, ByteBuffer> cache,
             @NonNull String fontDir,
-            @NonNull HashSet<Font> availableFonts) {
+            @NonNull ArrayList<Font> availableFonts) {
         if (fonts.size() == 0) {
             return null;
         }
 
         FontFamily.Builder b = null;
-        final LocaleList localeList = LocaleList.forLanguageTags(languageTags);
         for (int i = 0; i < fonts.size(); i++) {
             final FontConfig.Font fontConfig = fonts.get(i);
             final String fullPath = fontDir + fontConfig.getFontName();
@@ -194,7 +193,7 @@
 
             final Font font;
             try {
-                font = new Font.Builder(buffer, new File(fullPath), localeList)
+                font = new Font.Builder(buffer, new File(fullPath), languageTags)
                         .setWeight(fontConfig.getWeight())
                         .setItalic(fontConfig.isItalic())
                         .setTtcIndex(fontConfig.getTtcIndex())
@@ -228,7 +227,7 @@
     public static FontConfig.Alias[] buildSystemFallback(@NonNull String xmlPath,
             @NonNull String fontDir,
             @NonNull ArrayMap<String, FontFamily[]> fallbackMap,
-            @NonNull HashSet<Font> availableFonts) {
+            @NonNull ArrayList<Font> availableFonts) {
         try {
             final FileInputStream fontsIn = new FileInputStream(xmlPath);
             final FontConfig fontConfig = FontListParser.parse(fontsIn);
@@ -284,11 +283,11 @@
 
     static {
         final ArrayMap<String, FontFamily[]> systemFallbackMap = new ArrayMap<>();
-        final HashSet<Font> availableFonts = new HashSet<>();
+        final ArrayList<Font> availableFonts = new ArrayList<>();
         sAliases = buildSystemFallback("/system/etc/fonts.xml", "/system/fonts/",
                 systemFallbackMap, availableFonts);
         sSystemFallbackMap = Collections.unmodifiableMap(systemFallbackMap);
-        sAvailableFonts = Collections.unmodifiableSet(availableFonts);
+        sAvailableFonts = Collections.unmodifiableList(availableFonts);
     }
 
 }
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 04bbe24..494e513 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -175,6 +175,7 @@
         "pipeline/skia/SkiaRecordingCanvas.cpp",
         "pipeline/skia/SkiaVulkanPipeline.cpp",
         "pipeline/skia/VectorDrawableAtlas.cpp",
+        "pipeline/skia/VkFunctorDrawable.cpp",
         "renderstate/RenderState.cpp",
         "renderthread/CacheManager.cpp",
         "renderthread/CanvasContext.cpp",
@@ -228,6 +229,7 @@
         "ResourceCache.cpp",
         "SkiaCanvas.cpp",
         "Snapshot.cpp",
+        "TreeInfo.cpp",
         "VectorDrawable.cpp",
         "protos/graphicsstats.proto",
     ],
@@ -247,7 +249,7 @@
         // Enables fine-grained GLES error checking
         // If enabled, every GLES call is wrapped & error checked
         // Has moderate overhead
-        "hwui_enable_opengl_validation",
+        //"hwui_enable_opengl_validation",
     ],
 }
 
diff --git a/libs/hwui/CanvasTransform.cpp b/libs/hwui/CanvasTransform.cpp
index adcdc18..06e937a 100644
--- a/libs/hwui/CanvasTransform.cpp
+++ b/libs/hwui/CanvasTransform.cpp
@@ -28,6 +28,7 @@
 #include <cmath>
 
 #include <log/log.h>
+#include <SkHighContrastFilter.h>
 
 namespace android::uirenderer {
 
@@ -78,7 +79,6 @@
         info.fColors = _colorStorage.data();
         info.fColorOffsets = _offsetStorage.data();
         SkShader::GradientType type = paint.getShader()->asAGradient(&info);
-        ALOGW_IF(type, "Found gradient of type = %d", type);
 
         if (info.fColorCount <= 10) {
             switch (type) {
@@ -107,10 +107,43 @@
     }
 }
 
+static BitmapPalette paletteForColorHSV(SkColor color) {
+    float hsv[3];
+    SkColorToHSV(color, hsv);
+    return hsv[2] >= .5f ? BitmapPalette::Light : BitmapPalette::Dark;
+}
+
+static BitmapPalette filterPalette(const SkPaint* paint, BitmapPalette palette) {
+    if (palette == BitmapPalette::Unknown || !paint || !paint->getColorFilter()) {
+        return palette;
+    }
+
+    SkColor color = palette == BitmapPalette::Light ? SK_ColorWHITE : SK_ColorBLACK;
+    color = paint->getColorFilter()->filterColor(color);
+    return paletteForColorHSV(color);
+}
+
 bool transformPaint(ColorTransform transform, SkPaint* paint) {
     // TODO
     applyColorTransform(transform, *paint);
     return true;
 }
 
+bool transformPaint(ColorTransform transform, SkPaint* paint, BitmapPalette palette) {
+    palette = filterPalette(paint, palette);
+    bool shouldInvert = false;
+    if (palette == BitmapPalette::Light && transform == ColorTransform::Dark) {
+        shouldInvert = true;
+    }
+    if (palette == BitmapPalette::Dark && transform == ColorTransform::Light) {
+        shouldInvert = true;
+    }
+    if (shouldInvert) {
+        SkHighContrastConfig config;
+        config.fInvertStyle = SkHighContrastConfig::InvertStyle::kInvertLightness;
+        paint->setColorFilter(SkHighContrastFilter::Make(config)->makeComposed(paint->refColorFilter()));
+    }
+    return shouldInvert;
+}
+
 };  // namespace android::uirenderer
\ No newline at end of file
diff --git a/libs/hwui/CanvasTransform.h b/libs/hwui/CanvasTransform.h
index 32d9a05..e723d64 100644
--- a/libs/hwui/CanvasTransform.h
+++ b/libs/hwui/CanvasTransform.h
@@ -16,6 +16,8 @@
 
 #pragma once
 
+#include "hwui/Bitmap.h"
+
 #include <SkCanvas.h>
 #include <SkPaintFilterCanvas.h>
 
@@ -26,6 +28,7 @@
 enum class UsageHint {
     Unknown = 0,
     Background = 1,
+    Foreground = 2,
 };
 
 enum class ColorTransform {
@@ -37,4 +40,6 @@
 // True if the paint was modified, false otherwise
 bool transformPaint(ColorTransform transform, SkPaint* paint);
 
+bool transformPaint(ColorTransform transform, SkPaint* paint, BitmapPalette palette);
+
 }  // namespace android::uirenderer;
\ No newline at end of file
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 837d546..b772e5b 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -29,12 +29,16 @@
         , mGLContextAttached(false)
         , mUpdateTexImage(false)
         , mLayer(nullptr) {
-    renderState.registerDeferredLayerUpdater(this);
+    renderState.registerContextCallback(this);
 }
 
 DeferredLayerUpdater::~DeferredLayerUpdater() {
     setTransform(nullptr);
-    mRenderState.unregisterDeferredLayerUpdater(this);
+    mRenderState.removeContextCallback(this);
+    destroyLayer();
+}
+
+void DeferredLayerUpdater::onContextDestroyed() {
     destroyLayer();
 }
 
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 4c323b8..b2c5131 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -27,6 +27,7 @@
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 
+#include "renderstate/RenderState.h"
 #include "surfacetexture/SurfaceTexture.h"
 #include "Layer.h"
 #include "Rect.h"
@@ -38,7 +39,7 @@
 
 // Container to hold the properties a layer should be set to at the start
 // of a render pass
-class DeferredLayerUpdater : public VirtualLightRefBase {
+class DeferredLayerUpdater : public VirtualLightRefBase, public IGpuContextCallback {
 public:
     // Note that DeferredLayerUpdater assumes it is taking ownership of the layer
     // and will not call incrementRef on it as a result.
@@ -98,6 +99,9 @@
 
     void destroyLayer();
 
+protected:
+    void onContextDestroyed() override;
+
 private:
     RenderState& mRenderState;
 
diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp
index a43f58c..21fbbdc 100644
--- a/libs/hwui/DeviceInfo.cpp
+++ b/libs/hwui/DeviceInfo.cpp
@@ -26,8 +26,6 @@
 
 #include <log/log.h>
 
-#include <GLES2/gl2.h>
-
 namespace android {
 namespace uirenderer {
 
@@ -46,35 +44,12 @@
         1920,   // viewportH
 };
 
-static DeviceInfo* sDeviceInfo = nullptr;
-static std::once_flag sInitializedFlag;
-
 const DeviceInfo* DeviceInfo::get() {
-    LOG_ALWAYS_FATAL_IF(!sDeviceInfo, "DeviceInfo not yet initialized.");
-    return sDeviceInfo;
+        static DeviceInfo sDeviceInfo;
+        return &sDeviceInfo;
 }
 
-void DeviceInfo::initialize() {
-    std::call_once(sInitializedFlag, []() {
-        sDeviceInfo = new DeviceInfo();
-        sDeviceInfo->load();
-    });
-}
-
-void DeviceInfo::initialize(int maxTextureSize) {
-    std::call_once(sInitializedFlag, [maxTextureSize]() {
-        sDeviceInfo = new DeviceInfo();
-        sDeviceInfo->mDisplayInfo = DeviceInfo::queryDisplayInfo();
-        sDeviceInfo->mMaxTextureSize = maxTextureSize;
-    });
-}
-
-void DeviceInfo::load() {
-    mDisplayInfo = queryDisplayInfo();
-    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
-}
-
-DisplayInfo DeviceInfo::queryDisplayInfo() {
+DisplayInfo QueryDisplayInfo() {
     if (Properties::isolatedProcess) {
         return sDummyDisplay;
     }
@@ -86,5 +61,36 @@
     return displayInfo;
 }
 
+void QueryCompositionPreference(ui::Dataspace* dataSpace,
+                                ui::PixelFormat* pixelFormat) {
+    if (Properties::isolatedProcess) {
+        *dataSpace = ui::Dataspace::V0_SRGB;
+        *pixelFormat = ui::PixelFormat::RGBA_8888;
+    }
+
+    status_t status =
+            SurfaceComposerClient::getCompositionPreference(dataSpace, pixelFormat);
+    LOG_ALWAYS_FATAL_IF(status, "Failed to get composition preference, error %d", status);
+}
+
+DeviceInfo::DeviceInfo() {
+#if HWUI_NULL_GPU
+        mMaxTextureSize = NULL_GPU_MAX_TEXTURE_SIZE;
+#else
+        mMaxTextureSize = -1;
+#endif
+    mDisplayInfo = QueryDisplayInfo();
+    QueryCompositionPreference(&mTargetDataSpace, &mTargetPixelFormat);
+}
+
+int DeviceInfo::maxTextureSize() const {
+    LOG_ALWAYS_FATAL_IF(mMaxTextureSize < 0, "MaxTextureSize has not been initialized yet.");
+    return mMaxTextureSize;
+}
+
+void DeviceInfo::setMaxTextureSize(int maxTextureSize) {
+    const_cast<DeviceInfo*>(DeviceInfo::get())->mMaxTextureSize = maxTextureSize;
+}
+
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/DeviceInfo.h b/libs/hwui/DeviceInfo.h
index 297b266..1d747741 100644
--- a/libs/hwui/DeviceInfo.h
+++ b/libs/hwui/DeviceInfo.h
@@ -17,47 +17,43 @@
 #define DEVICEINFO_H
 
 #include <ui/DisplayInfo.h>
+#include <ui/GraphicTypes.h>
 
-#include "Extensions.h"
 #include "utils/Macros.h"
 
 namespace android {
 namespace uirenderer {
 
+namespace renderthread {
+    class RenderThread;
+}
+
 class DeviceInfo {
     PREVENT_COPY_AND_ASSIGN(DeviceInfo);
 
 public:
-    // returns nullptr if DeviceInfo is not initialized yet
-    // Note this does not have a memory fence so it's up to the caller
-    // to use one if required. Normally this should not be necessary
     static const DeviceInfo* get();
 
-    // only call this after GL has been initialized, or at any point if compiled
-    // with HWUI_NULL_GPU
-    static void initialize();
-    static void initialize(int maxTextureSize);
+    // this value is only valid after the GPU has been initialized and there is a valid graphics
+    // context or if you are using the HWUI_NULL_GPU
+    int maxTextureSize() const;
 
-    int maxTextureSize() const { return mMaxTextureSize; }
+    ui::Dataspace getTargetDataSpace() const { return mTargetDataSpace; }
+    ui::PixelFormat getTargetPixelFormat() const { return mTargetPixelFormat; }
     const DisplayInfo& displayInfo() const { return mDisplayInfo; }
-    const Extensions& extensions() const { return mExtensions; }
-
-    static uint32_t multiplyByResolution(uint32_t in) {
-        auto di = DeviceInfo::get()->displayInfo();
-        return di.w * di.h * in;
-    }
-
-    static DisplayInfo queryDisplayInfo();
 
 private:
-    DeviceInfo() {}
-    ~DeviceInfo() {}
+    friend class renderthread::RenderThread;
+    static void setMaxTextureSize(int maxTextureSize);
 
-    void load();
+    DeviceInfo();
 
     int mMaxTextureSize;
     DisplayInfo mDisplayInfo;
-    Extensions mExtensions;
+
+    // TODO(lpy) Replace below with android_ prefix types.
+    ui::Dataspace mTargetDataSpace;
+    ui::PixelFormat mTargetPixelFormat;
 };
 
 } /* namespace uirenderer */
diff --git a/libs/hwui/DisplayListOps.in b/libs/hwui/DisplayListOps.in
index f61c156..04cf611 100644
--- a/libs/hwui/DisplayListOps.in
+++ b/libs/hwui/DisplayListOps.in
@@ -49,4 +49,5 @@
 X(DrawPoints) 
 X(DrawVertices) 
 X(DrawAtlas) 
-X(DrawShadowRec)
\ No newline at end of file
+X(DrawShadowRec)
+X(DrawVectorDrawable)
\ No newline at end of file
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
deleted file mode 100644
index e90f40c..0000000
--- a/libs/hwui/Extensions.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HWUI_EXTENSIONS_H
-#define ANDROID_HWUI_EXTENSIONS_H
-
-namespace android {
-namespace uirenderer {
-
-///////////////////////////////////////////////////////////////////////////////
-// Classes
-///////////////////////////////////////////////////////////////////////////////
-
-class Extensions {
-public:
-    Extensions() {}
-
-    inline bool hasNPot() const { return false; }
-    inline bool hasFramebufferFetch() const { return false; }
-    inline bool hasDiscardFramebuffer() const { return false; }
-    inline bool hasDebugMarker() const { return false; }
-    inline bool has1BitStencil() const { return false; }
-    inline bool has4BitStencil() const { return false; }
-    inline bool hasUnpackRowLength() const { return mVersionMajor >= 3; }
-    inline bool hasPixelBufferObjects() const { return mVersionMajor >= 3; }
-    inline bool hasOcclusionQueries() const { return mVersionMajor >= 3; }
-    inline bool hasFloatTextures() const { return mVersionMajor >= 3; }
-    inline bool hasRenderableFloatTextures() const {
-        return (mVersionMajor >= 3 && mVersionMinor >= 2);
-    }
-    inline bool hasSRGB() const { return false; }
-    inline bool hasSRGBWriteControl() const { return hasSRGB() && false; }
-    inline bool hasLinearBlending() const { return hasSRGB() && false; }
-
-    inline int getMajorGlVersion() const { return mVersionMajor; }
-    inline int getMinorGlVersion() const { return mVersionMinor; }
-
-private:
-    int mVersionMajor = 2;
-    int mVersionMinor = 0;
-};  // class Extensions
-
-};  // namespace uirenderer
-};  // namespace android
-
-#endif  // ANDROID_HWUI_EXTENSIONS_H
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index ab80d3d..165fc48 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -45,7 +45,7 @@
 }
 
 static void checkIdleTimeout() {
-    std::lock_guard{sLock};
+    std::lock_guard _lock{sLock};
     if (sPendingUploads == 0 && shouldTimeOutLocked()) {
         sEglManager.destroy();
     } else {
@@ -54,7 +54,7 @@
 }
 
 static void beginUpload() {
-    std::lock_guard{sLock};
+    std::lock_guard _lock{sLock};
     sPendingUploads++;
 
     if (!sUploadThread) {
@@ -75,13 +75,13 @@
 }
 
 static void endUpload() {
-    std::lock_guard{sLock};
+    std::lock_guard _lock{sLock};
     sPendingUploads--;
     sLastUpload = systemTime();
 }
 
 static EGLDisplay getUploadEglDisplay() {
-    std::lock_guard{sLock};
+    std::lock_guard _lock{sLock};
     LOG_ALWAYS_FATAL_IF(!sEglManager.hasEglContext(), "Forgot to begin an upload?");
     return sEglManager.eglDisplay();
 }
@@ -107,39 +107,6 @@
 
 #define FENCE_TIMEOUT 2000000000
 
-class AutoEglImage {
-public:
-    AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer) : mDisplay(display) {
-        EGLint imageAttrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
-        image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer,
-                                  imageAttrs);
-    }
-
-    ~AutoEglImage() {
-        if (image != EGL_NO_IMAGE_KHR) {
-            eglDestroyImageKHR(mDisplay, image);
-        }
-    }
-
-    EGLImageKHR image = EGL_NO_IMAGE_KHR;
-
-private:
-    EGLDisplay mDisplay = EGL_NO_DISPLAY;
-};
-
-class AutoSkiaGlTexture {
-public:
-    AutoSkiaGlTexture() {
-        glGenTextures(1, &mTexture);
-        glBindTexture(GL_TEXTURE_2D, mTexture);
-    }
-
-    ~AutoSkiaGlTexture() { glDeleteTextures(1, &mTexture); }
-
-private:
-    GLuint mTexture = 0;
-};
-
 struct FormatInfo {
     PixelFormat pixelFormat;
     GLint format, type;
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index e6d2a6f..f2d50cd 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -146,7 +146,7 @@
                              frame[FrameInfoIndex::IntendedVsync] + mFrameInterval);
 
     // If we hit the deadline, cool!
-    if (frame[FrameInfoIndex::FrameCompleted] < mSwapDeadline) {
+    if (frame[FrameInfoIndex::FrameCompleted] < mSwapDeadline || totalDuration < mFrameInterval) {
         if (isTripleBuffered) {
             mData->reportJankType(JankType::kHighInputLatency);
             (*mGlobalData)->reportJankType(JankType::kHighInputLatency);
diff --git a/libs/hwui/LayerUpdateQueue.h b/libs/hwui/LayerUpdateQueue.h
index b14b80c..6857999 100644
--- a/libs/hwui/LayerUpdateQueue.h
+++ b/libs/hwui/LayerUpdateQueue.h
@@ -19,6 +19,7 @@
 
 #include <utils/StrongPointer.h>
 #include "Rect.h"
+#include "RenderNode.h"
 #include "utils/Macros.h"
 
 #include <unordered_map>
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 17bec19..a699e2f 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -61,6 +61,7 @@
 bool Properties::disableVsync = false;
 bool Properties::skpCaptureEnabled = false;
 bool Properties::forceDarkMode = false;
+bool Properties::enableForceDarkSupport = false;
 bool Properties::enableRTAnimations = true;
 
 bool Properties::runningInEmulator = false;
@@ -149,6 +150,9 @@
 
     forceDarkMode = property_get_bool(PROPERTY_FORCE_DARK, false);
 
+    // TODO: make this on by default
+    enableForceDarkSupport = property_get_bool(PROPERTY_ENABLE_FORCE_DARK, false);
+
     return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw) ||
            (prevDebugStencilClip != debugStencilClip);
 }
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index ea017a7..542bc71 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -192,6 +192,8 @@
 
 #define PROPERTY_FORCE_DARK "debug.hwui.force_dark"
 
+#define PROPERTY_ENABLE_FORCE_DARK "debug.hwui.force_dark_enabled"
+
 ///////////////////////////////////////////////////////////////////////////////
 // Misc
 ///////////////////////////////////////////////////////////////////////////////
@@ -266,6 +268,7 @@
 
     static bool skpCaptureEnabled;
     static bool forceDarkMode;
+    static bool enableForceDarkSupport;
 
     // For experimentation b/68769804
     ANDROID_API static bool enableRTAnimations;
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 3eaff03..c30af84 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -16,6 +16,8 @@
 
 #include "RecordingCanvas.h"
 
+#include "VectorDrawable.h"
+
 #include "SkCanvas.h"
 #include "SkData.h"
 #include "SkDrawShadowInfo.h"
@@ -278,8 +280,8 @@
 
 struct DrawImage final : Op {
     static const auto kType = Type::DrawImage;
-    DrawImage(sk_sp<const SkImage>&& image, SkScalar x, SkScalar y, const SkPaint* paint)
-            : image(std::move(image)), x(x), y(y) {
+    DrawImage(sk_sp<const SkImage>&& image, SkScalar x, SkScalar y, const SkPaint* paint, BitmapPalette palette)
+            : image(std::move(image)), x(x), y(y), palette(palette) {
         if (paint) {
             this->paint = *paint;
         }
@@ -287,6 +289,7 @@
     sk_sp<const SkImage> image;
     SkScalar x, y;
     SkPaint paint;
+    BitmapPalette palette;
     void draw(SkCanvas* c, const SkMatrix&) const { c->drawImage(image.get(), x, y, &paint); }
 };
 struct DrawImageNine final : Op {
@@ -309,8 +312,8 @@
 struct DrawImageRect final : Op {
     static const auto kType = Type::DrawImageRect;
     DrawImageRect(sk_sp<const SkImage>&& image, const SkRect* src, const SkRect& dst,
-                  const SkPaint* paint, SkCanvas::SrcRectConstraint constraint)
-            : image(std::move(image)), dst(dst), constraint(constraint) {
+                  const SkPaint* paint, SkCanvas::SrcRectConstraint constraint, BitmapPalette palette)
+            : image(std::move(image)), dst(dst), constraint(constraint), palette(palette) {
         this->src = src ? *src : SkRect::MakeIWH(this->image->width(), this->image->height());
         if (paint) {
             this->paint = *paint;
@@ -320,6 +323,7 @@
     SkRect src, dst;
     SkPaint paint;
     SkCanvas::SrcRectConstraint constraint;
+    BitmapPalette palette;
     void draw(SkCanvas* c, const SkMatrix&) const {
         c->drawImageRect(image.get(), src, dst, &paint, constraint);
     }
@@ -496,6 +500,27 @@
     SkDrawShadowRec fRec;
     void draw(SkCanvas* c, const SkMatrix&) const { c->private_draw_shadow_rec(fPath, fRec); }
 };
+
+struct DrawVectorDrawable final : Op {
+    static const auto kType = Type::DrawVectorDrawable;
+    DrawVectorDrawable(VectorDrawableRoot* tree)
+            : mRoot(tree)
+            , mBounds(tree->stagingProperties().getBounds())
+            , palette(tree->computePalette()) {
+        // Recording, so use staging properties
+        tree->getPaintFor(&paint, tree->stagingProperties());
+    }
+
+    void draw(SkCanvas* canvas, const SkMatrix&) const {
+        mRoot->draw(canvas, mBounds, paint);
+    }
+
+    sp<VectorDrawableRoot> mRoot;
+    SkRect mBounds;
+    SkPaint paint;
+    BitmapPalette palette;
+};
+
 }
 
 template <typename T, typename... Args>
@@ -609,8 +634,8 @@
     this->push<DrawPicture>(0, picture, matrix, paint);
 }
 void DisplayListData::drawImage(sk_sp<const SkImage> image, SkScalar x, SkScalar y,
-                                const SkPaint* paint) {
-    this->push<DrawImage>(0, std::move(image), x, y, paint);
+                                const SkPaint* paint, BitmapPalette palette) {
+    this->push<DrawImage>(0, std::move(image), x, y, paint, palette);
 }
 void DisplayListData::drawImageNine(sk_sp<const SkImage> image, const SkIRect& center,
                                     const SkRect& dst, const SkPaint* paint) {
@@ -618,8 +643,8 @@
 }
 void DisplayListData::drawImageRect(sk_sp<const SkImage> image, const SkRect* src,
                                     const SkRect& dst, const SkPaint* paint,
-                                    SkCanvas::SrcRectConstraint constraint) {
-    this->push<DrawImageRect>(0, std::move(image), src, dst, paint, constraint);
+                                    SkCanvas::SrcRectConstraint constraint, BitmapPalette palette) {
+    this->push<DrawImageRect>(0, std::move(image), src, dst, paint, constraint, palette);
 }
 void DisplayListData::drawImageLattice(sk_sp<const SkImage> image, const SkCanvas::Lattice& lattice,
                                        const SkRect& dst, const SkPaint* paint) {
@@ -638,28 +663,33 @@
                                const SkPaint& paint) {
     void* pod = this->push<DrawText>(bytes, bytes, x, y, paint);
     copy_v(pod, (const char*)text, bytes);
+    mHasText = true;
 }
 void DisplayListData::drawPosText(const void* text, size_t bytes, const SkPoint pos[],
                                   const SkPaint& paint) {
     int n = paint.countText(text, bytes);
     void* pod = this->push<DrawPosText>(n * sizeof(SkPoint) + bytes, bytes, paint, n);
     copy_v(pod, pos, n, (const char*)text, bytes);
+    mHasText = true;
 }
 void DisplayListData::drawPosTextH(const void* text, size_t bytes, const SkScalar xs[], SkScalar y,
                                    const SkPaint& paint) {
     int n = paint.countText(text, bytes);
     void* pod = this->push<DrawPosTextH>(n * sizeof(SkScalar) + bytes, bytes, y, paint, n);
     copy_v(pod, xs, n, (const char*)text, bytes);
+    mHasText = true;
 }
 void DisplayListData::drawTextRSXform(const void* text, size_t bytes, const SkRSXform xforms[],
                                       const SkRect* cull, const SkPaint& paint) {
     int n = paint.countText(text, bytes);
     void* pod = this->push<DrawTextRSXform>(bytes + n * sizeof(SkRSXform), bytes, n, cull, paint);
     copy_v(pod, xforms, n, (const char*)text, bytes);
+    mHasText = true;
 }
 void DisplayListData::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
                                    const SkPaint& paint) {
     this->push<DrawTextBlob>(0, blob, x, y, paint);
+    mHasText = true;
 }
 
 void DisplayListData::drawPatch(const SkPoint points[12], const SkColor colors[4],
@@ -691,6 +721,9 @@
 void DisplayListData::drawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
     this->push<DrawShadowRec>(0, path, rec);
 }
+void DisplayListData::drawVectorDrawable(VectorDrawableRoot* tree) {
+    this->push<DrawVectorDrawable>(0, tree);
+}
 
 typedef void (*draw_fn)(const void*, SkCanvas*, const SkMatrix&);
 typedef void (*void_fn)(const void*);
@@ -733,20 +766,35 @@
 }
 
 template <class T>
-using has_paint_t = decltype(std::declval<T>().paint);
+using has_paint_helper = decltype(std::declval<T>().paint);
+
+template <class T>
+constexpr bool has_paint = std::experimental::is_detected_v<has_paint_helper, T>;
+
+template <class T>
+using has_palette_helper = decltype(std::declval<T>().palette);
+
+template <class T>
+constexpr bool has_palette = std::experimental::is_detected_v<has_palette_helper, T>;
 
 template <class T>
 constexpr color_transform_fn colorTransformForOp() {
-    if
-        constexpr(std::experimental::is_detected_v<has_paint_t, T>) {
-            return [](const void* op, ColorTransform transform) {
-                // TODO: We should be const. Or not. Or just use a different map
-                // Unclear, but this is the quick fix
-                transformPaint(transform,
-                               const_cast<SkPaint*>(&(reinterpret_cast<const T*>(op)->paint)));
-            };
-        }
-    else {
+    if constexpr(has_paint<T> && has_palette<T>) {
+        // It's a bitmap
+        return [](const void* opRaw, ColorTransform transform) {
+            // TODO: We should be const. Or not. Or just use a different map
+            // Unclear, but this is the quick fix
+            const T* op = reinterpret_cast<const T*>(opRaw);
+            transformPaint(transform, const_cast<SkPaint*>(&(op->paint)), op->palette);
+        };
+    } else if constexpr(has_paint<T>) {
+        return [](const void* opRaw, ColorTransform transform) {
+            // TODO: We should be const. Or not. Or just use a different map
+            // Unclear, but this is the quick fix
+            const T* op = reinterpret_cast<const T*>(opRaw);
+            transformPaint(transform, const_cast<SkPaint*>(&(op->paint)));
+        };
+    } else {
         return nullptr;
     }
 }
@@ -875,7 +923,7 @@
 
 void RecordingCanvas::onDrawBitmap(const SkBitmap& bm, SkScalar x, SkScalar y,
                                    const SkPaint* paint) {
-    fDL->drawImage(SkImage::MakeFromBitmap(bm), x, y, paint);
+    fDL->drawImage(SkImage::MakeFromBitmap(bm), x, y, paint, BitmapPalette::Unknown);
 }
 void RecordingCanvas::onDrawBitmapNine(const SkBitmap& bm, const SkIRect& center, const SkRect& dst,
                                        const SkPaint* paint) {
@@ -883,16 +931,26 @@
 }
 void RecordingCanvas::onDrawBitmapRect(const SkBitmap& bm, const SkRect* src, const SkRect& dst,
                                        const SkPaint* paint, SrcRectConstraint constraint) {
-    fDL->drawImageRect(SkImage::MakeFromBitmap(bm), src, dst, paint, constraint);
+    fDL->drawImageRect(SkImage::MakeFromBitmap(bm), src, dst, paint, constraint, BitmapPalette::Unknown);
 }
 void RecordingCanvas::onDrawBitmapLattice(const SkBitmap& bm, const SkCanvas::Lattice& lattice,
                                           const SkRect& dst, const SkPaint* paint) {
     fDL->drawImageLattice(SkImage::MakeFromBitmap(bm), lattice, dst, paint);
 }
 
+void RecordingCanvas::drawImage(const sk_sp<SkImage>& image, SkScalar x, SkScalar y,
+                                const SkPaint* paint, BitmapPalette palette) {
+    fDL->drawImage(image, x, y, paint, palette);
+}
+
+void RecordingCanvas::drawImageRect(const sk_sp<SkImage>& image, const SkRect& src, const SkRect& dst,
+                   const SkPaint* paint, SrcRectConstraint constraint, BitmapPalette palette) {
+    fDL->drawImageRect(image, &src, dst, paint, constraint, palette);
+}
+
 void RecordingCanvas::onDrawImage(const SkImage* img, SkScalar x, SkScalar y,
                                   const SkPaint* paint) {
-    fDL->drawImage(sk_ref_sp(img), x, y, paint);
+    fDL->drawImage(sk_ref_sp(img), x, y, paint, BitmapPalette::Unknown);
 }
 void RecordingCanvas::onDrawImageNine(const SkImage* img, const SkIRect& center, const SkRect& dst,
                                       const SkPaint* paint) {
@@ -900,7 +958,7 @@
 }
 void RecordingCanvas::onDrawImageRect(const SkImage* img, const SkRect* src, const SkRect& dst,
                                       const SkPaint* paint, SrcRectConstraint constraint) {
-    fDL->drawImageRect(sk_ref_sp(img), src, dst, paint, constraint);
+    fDL->drawImageRect(sk_ref_sp(img), src, dst, paint, constraint, BitmapPalette::Unknown);
 }
 void RecordingCanvas::onDrawImageLattice(const SkImage* img, const SkCanvas::Lattice& lattice,
                                          const SkRect& dst, const SkPaint* paint) {
@@ -930,5 +988,9 @@
     fDL->drawShadowRec(path, rec);
 }
 
+void RecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
+    fDL->drawVectorDrawable(tree);
+}
+
 };  // namespace uirenderer
 };  // namespace android
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 32ce1d3..80c80ca 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include "CanvasTransform.h"
+#include "hwui/Bitmap.h"
 #include "hwui/Canvas.h"
 #include "utils/Macros.h"
 #include "utils/TypeLogic.h"
@@ -53,6 +54,7 @@
 
 class DisplayListData final {
 public:
+    DisplayListData() : mHasText(false) {}
     ~DisplayListData();
 
     void draw(SkCanvas* canvas) const;
@@ -62,6 +64,8 @@
 
     void applyColorTransform(ColorTransform transform);
 
+    bool hasText() const { return mHasText; }
+
 private:
     friend class RecordingCanvas;
 
@@ -101,10 +105,10 @@
     void drawTextRSXform(const void*, size_t, const SkRSXform[], const SkRect*, const SkPaint&);
     void drawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&);
 
-    void drawImage(sk_sp<const SkImage>, SkScalar, SkScalar, const SkPaint*);
+    void drawImage(sk_sp<const SkImage>, SkScalar, SkScalar, const SkPaint*, BitmapPalette palette);
     void drawImageNine(sk_sp<const SkImage>, const SkIRect&, const SkRect&, const SkPaint*);
     void drawImageRect(sk_sp<const SkImage>, const SkRect*, const SkRect&, const SkPaint*,
-                       SkCanvas::SrcRectConstraint);
+                       SkCanvas::SrcRectConstraint, BitmapPalette palette);
     void drawImageLattice(sk_sp<const SkImage>, const SkCanvas::Lattice&, const SkRect&,
                           const SkPaint*);
 
@@ -116,6 +120,7 @@
     void drawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int,
                    SkBlendMode, const SkRect*, const SkPaint*);
     void drawShadowRec(const SkPath&, const SkDrawShadowRec&);
+    void drawVectorDrawable(VectorDrawableRoot* tree);
 
     template <typename T, typename... Args>
     void* push(size_t, Args&&...);
@@ -126,6 +131,8 @@
     SkAutoTMalloc<uint8_t> fBytes;
     size_t fUsed = 0;
     size_t fReserved = 0;
+
+    bool mHasText : 1;
 };
 
 class RecordingCanvas final : public SkCanvasVirtualEnforcer<SkNoDrawCanvas> {
@@ -178,6 +185,12 @@
     void onDrawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint*,
                           SrcRectConstraint) override;
 
+    void drawImage(const sk_sp<SkImage>& image, SkScalar left, SkScalar top,
+                   const SkPaint* paint, BitmapPalette pallete);
+
+    void drawImageRect(const sk_sp<SkImage>& image, const SkRect& src, const SkRect& dst,
+                       const SkPaint* paint, SrcRectConstraint constraint, BitmapPalette palette);
+
     void onDrawImage(const SkImage*, SkScalar, SkScalar, const SkPaint*) override;
     void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&, const SkPaint*) override;
     void onDrawImageNine(const SkImage*, const SkIRect&, const SkRect&, const SkPaint*) override;
@@ -193,6 +206,8 @@
                      SkBlendMode, const SkRect*, const SkPaint*) override;
     void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override;
 
+    void drawVectorDrawable(VectorDrawableRoot* tree);
+
 private:
     typedef SkCanvasVirtualEnforcer<SkNoDrawCanvas> INHERITED;
 
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index d5afb20..d9a7cc3 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -112,7 +112,9 @@
     LOG_ALWAYS_FATAL_IF(!info.damageAccumulator, "DamageAccumulator missing");
     MarkAndSweepRemoved observer(&info);
 
+    const int before = info.disableForceDark;
     prepareTreeImpl(observer, info, false);
+    LOG_ALWAYS_FATAL_IF(before != info.disableForceDark, "Mis-matched force dark");
 }
 
 void RenderNode::addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
@@ -158,7 +160,7 @@
         CC_UNLIKELY(properties().getWidth() == 0) || CC_UNLIKELY(properties().getHeight() == 0) ||
         CC_UNLIKELY(!properties().fitsOnLayer())) {
         if (CC_UNLIKELY(hasLayer())) {
-            renderthread::CanvasContext::destroyLayer(this);
+            this->setLayerSurface(nullptr);
         }
         return;
     }
@@ -195,6 +197,11 @@
     if (info.mode == TreeInfo::MODE_FULL) {
         pushStagingPropertiesChanges(info);
     }
+
+    if (!mProperties.getAllowForceDark()) {
+        info.disableForceDark++;
+    }
+
     uint32_t animatorDirtyMask = 0;
     if (CC_LIKELY(info.runAnimations)) {
         animatorDirtyMask = mAnimatorManager.animate(info);
@@ -232,6 +239,9 @@
     }
     pushLayerUpdate(info);
 
+    if (!mProperties.getAllowForceDark()) {
+        info.disableForceDark--;
+    }
     info.damageAccumulator->popTransform();
 }
 
@@ -272,8 +282,12 @@
     mStagingDisplayList = nullptr;
     if (mDisplayList) {
         mDisplayList->syncContents();
-        if (CC_UNLIKELY(Properties::forceDarkMode)) {
+
+        if (CC_UNLIKELY(info && !info->disableForceDark)) {
             auto usage = usageHint();
+            if (mDisplayList->hasText()) {
+                usage = UsageHint::Foreground;
+            }
             if (usage == UsageHint::Unknown) {
                 if (mDisplayList->mChildNodes.size() > 1) {
                     usage = UsageHint::Background;
@@ -313,7 +327,7 @@
 
 void RenderNode::destroyHardwareResources(TreeInfo* info) {
     if (hasLayer()) {
-        renderthread::CanvasContext::destroyLayer(this);
+        this->setLayerSurface(nullptr);
     }
     setStagingDisplayList(nullptr);
 
@@ -323,7 +337,7 @@
 
 void RenderNode::destroyLayers() {
     if (hasLayer()) {
-        renderthread::CanvasContext::destroyLayer(this);
+        this->setLayerSurface(nullptr);
     }
     if (mDisplayList) {
         mDisplayList->updateChildren([](RenderNode* child) { child->destroyLayers(); });
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 83b0c22..211dd2d 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -107,7 +107,7 @@
     bool isRenderable() const { return mDisplayList && !mDisplayList->isEmpty(); }
 
     bool hasProjectionReceiver() const {
-        return mDisplayList && mDisplayList->projectionReceiveIndex >= 0;
+        return mDisplayList && mDisplayList->containsProjectionReceiver();
     }
 
     const char* getName() const { return mName.string(); }
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 7966845..04379ae 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -535,6 +535,14 @@
         return CC_UNLIKELY(promotedToLayer()) ? LayerType::RenderLayer : mLayerProperties.mType;
     }
 
+    bool setAllowForceDark(bool allow) {
+        return RP_SET(mPrimitiveFields.mAllowForceDark, allow);
+    }
+
+    bool getAllowForceDark() const {
+        return mPrimitiveFields.mAllowForceDark;
+    }
+
 private:
     // Rendering properties
     struct PrimitiveFields {
@@ -554,6 +562,7 @@
         bool mMatrixOrPivotDirty = false;
         bool mProjectBackwards = false;
         bool mProjectionReceiver = false;
+        bool mAllowForceDark = true;
         Rect mClipBounds;
         Outline mOutline;
         RevealClip mRevealClip;
diff --git a/libs/hwui/TreeInfo.cpp b/libs/hwui/TreeInfo.cpp
new file mode 100644
index 0000000..808a12a
--- /dev/null
+++ b/libs/hwui/TreeInfo.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TreeInfo.h"
+
+#include "renderthread/CanvasContext.h"
+
+namespace android::uirenderer {
+
+TreeInfo::TreeInfo(TraversalMode mode, renderthread::CanvasContext& canvasContext)
+        : mode(mode)
+        , prepareTextures(mode == MODE_FULL)
+        , canvasContext(canvasContext)
+        , disableForceDark(canvasContext.useForceDark() ? 0 : 1) {}
+
+}  // namespace android::uirenderer
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index f2766d6..a0d9605 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include "Properties.h"
 #include "utils/Macros.h"
 
 #include <utils/Timers.h>
@@ -39,7 +40,7 @@
     virtual void onError(const std::string& message) = 0;
 
 protected:
-    virtual ~ErrorHandler() {}
+    virtual ~ErrorHandler() = default;
 };
 
 class TreeObserver {
@@ -51,7 +52,7 @@
     virtual void onMaybeRemovedFromTree(RenderNode* node) = 0;
 
 protected:
-    virtual ~TreeObserver() {}
+    virtual ~TreeObserver() = default;
 };
 
 // This would be a struct, but we want to PREVENT_COPY_AND_ASSIGN
@@ -70,8 +71,7 @@
         MODE_RT_ONLY,
     };
 
-    TreeInfo(TraversalMode mode, renderthread::CanvasContext& canvasContext)
-            : mode(mode), prepareTextures(mode == MODE_FULL), canvasContext(canvasContext) {}
+    TreeInfo(TraversalMode mode, renderthread::CanvasContext& canvasContext);
 
     TraversalMode mode;
     // TODO: Remove this? Currently this is used to signal to stop preparing
@@ -93,6 +93,8 @@
 
     bool updateWindowPositions = false;
 
+    int disableForceDark;
+
     struct Out {
         bool hasFunctors = false;
         // This is only updated if evaluateAnimations is true
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 9f82d0f..dbbe9f3 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -458,29 +458,22 @@
         mStagingCache.dirty = false;
     }
 
-    SkPaint tmpPaint;
-    SkPaint* paint = updatePaint(&tmpPaint, &mStagingProperties);
+    SkPaint paint;
+    getPaintFor(&paint, mStagingProperties);
     outCanvas->drawBitmap(*mStagingCache.bitmap, 0, 0, mStagingCache.bitmap->width(),
                           mStagingCache.bitmap->height(), mStagingProperties.getBounds().left(),
                           mStagingProperties.getBounds().top(),
                           mStagingProperties.getBounds().right(),
-                          mStagingProperties.getBounds().bottom(), paint);
+                          mStagingProperties.getBounds().bottom(), &paint);
 }
 
-SkPaint* Tree::getPaint() {
-    return updatePaint(&mPaint, &mProperties);
-}
-
-// Update the given paint with alpha and color filter. Return nullptr if no color filter is
-// specified and root alpha is 1. Otherwise, return updated paint.
-SkPaint* Tree::updatePaint(SkPaint* outPaint, TreeProperties* prop) {
+void Tree::getPaintFor(SkPaint* outPaint, const TreeProperties &prop) const {
     // HWUI always draws VD with bilinear filtering.
     outPaint->setFilterQuality(kLow_SkFilterQuality);
-    if (prop->getRootAlpha() < 1.0f || prop->getColorFilter() != nullptr) {
-        outPaint->setColorFilter(sk_ref_sp(prop->getColorFilter()));
-        outPaint->setAlpha(prop->getRootAlpha() * 255);
+    if (prop.getRootAlpha() < 1.0f || prop.getColorFilter() != nullptr) {
+        outPaint->setColorFilter(sk_ref_sp(prop.getColorFilter()));
+        outPaint->setAlpha(prop.getRootAlpha() * 255);
     }
-    return outPaint;
 }
 
 Bitmap& Tree::getBitmapUpdateIfDirty() {
@@ -553,11 +546,15 @@
     mAtlasKey = INVALID_ATLAS_KEY;
 }
 
-void Tree::draw(SkCanvas* canvas, const SkRect& bounds) {
+void Tree::draw(SkCanvas* canvas, const SkRect& bounds, const SkPaint& inPaint) {
+    // Update the paint for any animatable properties
+    SkPaint paint = inPaint;
+    paint.setAlpha(mProperties.getRootAlpha() * 255);
+
     SkRect src;
     sk_sp<SkSurface> vdSurface = mCache.getSurface(&src);
     if (vdSurface) {
-        canvas->drawImageRect(vdSurface->makeImageSnapshot().get(), src, bounds, getPaint(),
+        canvas->drawImageRect(vdSurface->makeImageSnapshot().get(), src, bounds, &paint,
                               SkCanvas::kFast_SrcRectConstraint);
     } else {
         // Handle the case when VectorDrawableAtlas has been destroyed, because of memory pressure.
@@ -570,7 +567,7 @@
         int scaledWidth = SkScalarCeilToInt(mProperties.getScaledWidth());
         int scaledHeight = SkScalarCeilToInt(mProperties.getScaledHeight());
         canvas->drawBitmapRect(skiaBitmap, SkRect::MakeWH(scaledWidth, scaledHeight), bounds,
-                               getPaint(), SkCanvas::kFast_SrcRectConstraint);
+                               &paint, SkCanvas::kFast_SrcRectConstraint);
         mCache.clear();
         markDirty();
     }
@@ -620,6 +617,80 @@
     }
 }
 
+class MinMaxAverage {
+public:
+    void add(float sample) {
+        if (mCount == 0) {
+            mMin = sample;
+            mMax = sample;
+        } else {
+            mMin = std::min(mMin, sample);
+            mMax = std::max(mMax, sample);
+        }
+        mTotal += sample;
+        mCount++;
+    }
+
+    float average() { return mTotal / mCount; }
+
+    float min() { return mMin; }
+
+    float max() { return mMax; }
+
+    float delta() { return mMax - mMin; }
+
+private:
+    float mMin = 0.0f;
+    float mMax = 0.0f;
+    float mTotal = 0.0f;
+    int mCount = 0;
+};
+
+BitmapPalette Tree::computePalette() {
+    // TODO Cache this and share the code with Bitmap.cpp
+
+    ATRACE_CALL();
+
+    // TODO: This calculation of converting to HSV & tracking min/max is probably overkill
+    // Experiment with something simpler since we just want to figure out if it's "color-ful"
+    // and then the average perceptual lightness.
+
+    MinMaxAverage hue, saturation, value;
+    int sampledCount = 0;
+
+    // Sample a grid of 100 pixels to get an overall estimation of the colors in play
+    mRootNode->forEachFillColor([&](SkColor color) {
+        if (SkColorGetA(color) < 75) {
+            return;
+        }
+        sampledCount++;
+        float hsv[3];
+        SkColorToHSV(color, hsv);
+        hue.add(hsv[0]);
+        saturation.add(hsv[1]);
+        value.add(hsv[2]);
+    });
+
+    if (sampledCount == 0) {
+        ALOGV("VectorDrawable is mostly translucent");
+        return BitmapPalette::Unknown;
+    }
+
+    ALOGV("samples = %d, hue [min = %f, max = %f, avg = %f]; saturation [min = %f, max = %f, avg = "
+          "%f]; value [min = %f, max = %f, avg = %f]",
+          sampledCount, hue.min(), hue.max(), hue.average(), saturation.min(), saturation.max(),
+          saturation.average(), value.min(), value.max(), value.average());
+
+    if (hue.delta() <= 20 && saturation.delta() <= .1f) {
+        if (value.average() >= .5f) {
+            return BitmapPalette::Light;
+        } else {
+            return BitmapPalette::Dark;
+        }
+    }
+    return BitmapPalette::Unknown;
+}
+
 };  // namespace VectorDrawable
 
 };  // namespace uirenderer
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index af0ae05..9c0bb16 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -120,6 +120,8 @@
     virtual void syncProperties() = 0;
     virtual void setAntiAlias(bool aa) = 0;
 
+    virtual void forEachFillColor(const std::function<void(SkColor)>& func) const { }
+
 protected:
     std::string mName;
     PropertyChangedListener* mPropertyChangedListener = nullptr;
@@ -349,6 +351,9 @@
         }
     }
     virtual void setAntiAlias(bool aa) { mAntiAlias = aa; }
+    void forEachFillColor(const std::function<void(SkColor)>& func) const override {
+        func(mStagingProperties.getFillColor());
+    }
 
 protected:
     const SkPath& getUpdatedPath(bool useStagingData, SkPath* tempStagingPath) override;
@@ -480,6 +485,12 @@
         }
     }
 
+    void forEachFillColor(const std::function<void(SkColor)>& func) const override {
+        for (auto& child : mChildren) {
+            child->forEachFillColor(func);
+        }
+    }
+
 private:
     GroupProperties mProperties = GroupProperties(this);
     GroupProperties mStagingProperties = GroupProperties(this);
@@ -495,8 +506,8 @@
 
     // Copy properties from the tree and use the give node as the root node
     Tree(const Tree* copy, Group* rootNode) : Tree(rootNode) {
-        mStagingProperties.syncAnimatableProperties(*copy->stagingProperties());
-        mStagingProperties.syncNonAnimatableProperties(*copy->stagingProperties());
+        mStagingProperties.syncAnimatableProperties(copy->stagingProperties());
+        mStagingProperties.syncNonAnimatableProperties(copy->stagingProperties());
     }
     // Draws the VD onto a bitmap cache, then the bitmap cache will be rendered onto the input
     // canvas. Returns the number of pixels needed for the bitmap cache.
@@ -506,7 +517,6 @@
 
     Bitmap& getBitmapUpdateIfDirty();
     void setAllowCaching(bool allowCaching) { mAllowCaching = allowCaching; }
-    SkPaint* getPaint();
     void syncProperties() {
         if (mStagingProperties.mNonAnimatablePropertiesDirty) {
             mCache.dirty |= (mProperties.mNonAnimatableProperties.viewportWidth !=
@@ -618,7 +628,7 @@
     };
     void onPropertyChanged(TreeProperties* prop);
     TreeProperties* mutateStagingProperties() { return &mStagingProperties; }
-    const TreeProperties* stagingProperties() const { return &mStagingProperties; }
+    const TreeProperties& stagingProperties() const { return mStagingProperties; }
 
     // This should only be called from animations on RT
     TreeProperties* mutateProperties() { return &mProperties; }
@@ -636,7 +646,10 @@
      * Draws VD cache into a canvas. This should always be called from RT and it works with Skia
      * pipelines only.
      */
-    void draw(SkCanvas* canvas, const SkRect& bounds);
+    void draw(SkCanvas* canvas, const SkRect& bounds, const SkPaint& paint);
+
+    void getPaintFor(SkPaint* outPaint, const TreeProperties &props) const;
+    BitmapPalette computePalette();
 
     /**
      * Draws VD into a GPU backed surface.
@@ -680,7 +693,6 @@
         skiapipeline::AtlasKey mAtlasKey = INVALID_ATLAS_KEY;
     };
 
-    SkPaint* updatePaint(SkPaint* outPaint, TreeProperties* prop);
     bool allocateBitmapIfNeeded(Cache& cache, int width, int height);
     bool canReuseBitmap(Bitmap*, int width, int height);
     void updateBitmapCache(Bitmap& outCache, bool useStagingData);
@@ -696,8 +708,6 @@
     TreeProperties mProperties = TreeProperties(this);
     TreeProperties mStagingProperties = TreeProperties(this);
 
-    SkPaint mPaint;
-
     Cache mStagingCache;
     Cache mCache;
 
diff --git a/libs/hwui/debug/wrap_gles.h b/libs/hwui/debug/wrap_gles.h
index 27a29aa..3da6e80 100644
--- a/libs/hwui/debug/wrap_gles.h
+++ b/libs/hwui/debug/wrap_gles.h
@@ -28,6 +28,9 @@
 #include <GLES3/gl31.h>
 #include <GLES3/gl32.h>
 
+// constant used by the NULL GPU implementation as well as HWUI's unit tests
+constexpr int NULL_GPU_MAX_TEXTURE_SIZE = 2048;
+
 // Generate stubs that route all the calls to our function table
 #include "gles_redefine.h"
 
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.h b/libs/hwui/hwui/AnimatedImageDrawable.h
index 8a44b8b..f0aa35a 100644
--- a/libs/hwui/hwui/AnimatedImageDrawable.h
+++ b/libs/hwui/hwui/AnimatedImageDrawable.h
@@ -106,7 +106,7 @@
     Snapshot decodeNextFrame();
     Snapshot reset();
 
-    size_t byteSize() const { return sizeof(this) + mBytesUsed; }
+    size_t byteSize() const { return sizeof(*this) + mBytesUsed; }
 
 protected:
     virtual void onDraw(SkCanvas* canvas) override;
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 440620a..9c28453 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -230,8 +230,6 @@
             mPixelStorage.hardware.buffer = nullptr;
             break;
     }
-
-    android::uirenderer::renderthread::RenderProxy::onBitmapDestroyed(getStableID());
 }
 
 bool Bitmap::hasHardwareMipMap() const {
@@ -330,15 +328,6 @@
     if (image->colorSpace() != nullptr && !image->colorSpace()->isSRGB()) {
         *outputColorFilter = SkToSRGBColorFilter::Make(image->refColorSpace());
     }
-
-    // TODO: Move this to the canvas (or other?) layer where we have the target lightness
-    // mode and can selectively do the right thing.
-    //    if (palette() != BitmapPalette::Unknown && uirenderer::Properties::forceDarkMode) {
-    //        SkHighContrastConfig config;
-    //        config.fInvertStyle = SkHighContrastConfig::InvertStyle::kInvertLightness;
-    //        *outputColorFilter =
-    //        SkHighContrastFilter::Make(config)->makeComposed(*outputColorFilter);
-    //    }
     return image;
 }
 
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index 170335d..43d457a 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -34,6 +34,8 @@
     Hardware,
 };
 
+// TODO: Find a better home for this. It's here because hwui/Bitmap is exported and CanvasTransform
+// isn't, but cleanup should be done
 enum class BitmapPalette {
     Unknown,
     Light,
diff --git a/libs/hwui/pipeline/skia/DumpOpsCanvas.h b/libs/hwui/pipeline/skia/DumpOpsCanvas.h
index dcfe6b3..e4ba13d 100644
--- a/libs/hwui/pipeline/skia/DumpOpsCanvas.h
+++ b/libs/hwui/pipeline/skia/DumpOpsCanvas.h
@@ -138,7 +138,7 @@
             renderNodeDrawable->getRenderNode()->output(mOutput, mLevel + 1);
             return;
         }
-        auto glFunctorDrawable = getGLFunctorDrawable(drawable);
+        auto glFunctorDrawable = getFunctorDrawable(drawable);
         if (nullptr != glFunctorDrawable) {
             mOutput << std::string(mLevel * 2, ' ') << "drawGLFunctorDrawable" << std::endl;
             return;
@@ -157,10 +157,10 @@
         return nullptr;
     }
 
-    GLFunctorDrawable* getGLFunctorDrawable(SkDrawable* drawable) {
+    FunctorDrawable* getFunctorDrawable(SkDrawable* drawable) {
         for (auto& child : mDisplayList.mChildFunctors) {
-            if (drawable == &child) {
-                return &child;
+            if (drawable == child) {
+                return child;
             }
         }
         return nullptr;
diff --git a/libs/hwui/pipeline/skia/FunctorDrawable.h b/libs/hwui/pipeline/skia/FunctorDrawable.h
new file mode 100644
index 0000000..162d137
--- /dev/null
+++ b/libs/hwui/pipeline/skia/FunctorDrawable.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "GlFunctorLifecycleListener.h"
+
+#include <SkCanvas.h>
+#include <SkDrawable.h>
+
+#include <utils/Functor.h>
+
+namespace android {
+namespace uirenderer {
+
+namespace skiapipeline {
+
+/**
+ * This drawable wraps a functor enabling it to be recorded into a list
+ * of Skia drawing commands.
+ */
+class FunctorDrawable : public SkDrawable {
+public:
+    FunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, SkCanvas* canvas)
+            : mFunctor(functor), mListener(listener), mBounds(canvas->getLocalClipBounds()) {}
+    virtual ~FunctorDrawable() {}
+
+    virtual void syncFunctor() const = 0;
+
+protected:
+    virtual SkRect onGetBounds() override { return mBounds; }
+
+    Functor* mFunctor;
+    sp<GlFunctorLifecycleListener> mListener;
+    const SkRect mBounds;
+};
+
+};  // namespace skiapipeline
+};  // namespace uirenderer
+};  // namespace android
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
index b0fec7a..90d5e71 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
@@ -18,7 +18,6 @@
 #include <GrContext.h>
 #include <private/hwui/DrawGlInfo.h>
 #include "GlFunctorLifecycleListener.h"
-#include "Properties.h"
 #include "RenderNode.h"
 #include "SkAndroidFrameworkUtils.h"
 #include "SkClipStack.h"
@@ -80,11 +79,6 @@
         return;
     }
 
-    if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
-        canvas->clear(SK_ColorRED);
-        return;
-    }
-
     GLuint fboID = 0;
     SkISize fboSize;
     if (!GetFboDetails(canvas, &fboID, &fboSize)) {
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.h b/libs/hwui/pipeline/skia/GLFunctorDrawable.h
index d9e65c9..dd6ef25 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.h
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.h
@@ -16,12 +16,8 @@
 
 #pragma once
 
-#include "GlFunctorLifecycleListener.h"
+#include "FunctorDrawable.h"
 
-#include <SkCanvas.h>
-#include <SkDrawable.h>
-
-#include <utils/Functor.h>
 #include <utils/RefBase.h>
 
 namespace android {
@@ -33,22 +29,16 @@
  * This drawable wraps a OpenGL functor enabling it to be recorded into a list
  * of Skia drawing commands.
  */
-class GLFunctorDrawable : public SkDrawable {
+class GLFunctorDrawable : public FunctorDrawable {
 public:
     GLFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, SkCanvas* canvas)
-            : mFunctor(functor), mListener(listener), mBounds(canvas->getLocalClipBounds()) {}
+            : FunctorDrawable(functor, listener, canvas) {}
     virtual ~GLFunctorDrawable();
 
-    void syncFunctor() const;
+    void syncFunctor() const override;
 
 protected:
-    virtual SkRect onGetBounds() override { return mBounds; }
     virtual void onDraw(SkCanvas* canvas) override;
-
-private:
-    Functor* mFunctor;
-    sp<GlFunctorLifecycleListener> mListener;
-    const SkRect mBounds;
 };
 
 };  // namespace skiapipeline
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
index 82179a3..3890513 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
@@ -29,7 +29,7 @@
 
 void SkiaDisplayList::syncContents() {
     for (auto& functor : mChildFunctors) {
-        functor.syncFunctor();
+        functor->syncFunctor();
     }
     for (auto& animatedImage : mAnimatedImages) {
         animatedImage->syncProperties();
@@ -132,7 +132,6 @@
     mChildFunctors.clear();
     mChildNodes.clear();
 
-    projectionReceiveIndex = -1;
     allocator.~LinearAllocator();
     new (&allocator) LinearAllocator();
 }
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h
index 4f30f98..ac7bb7b 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.h
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h
@@ -17,7 +17,7 @@
 #pragma once
 
 #include "hwui/AnimatedImageDrawable.h"
-#include "GLFunctorDrawable.h"
+#include "FunctorDrawable.h"
 #include "RecordingCanvas.h"
 #include "RenderNodeDrawable.h"
 #include "TreeInfo.h"
@@ -49,9 +49,6 @@
  */
 class SkiaDisplayList {
 public:
-    // index of DisplayListOp restore, after which projected descendants should be drawn
-    int projectionReceiveIndex = -1;
-
     size_t getUsedSize() { return allocator.usedSize(); }
 
     ~SkiaDisplayList() {
@@ -77,7 +74,7 @@
      * that creates them. Allocator dtor invokes all SkDrawable dtors.
      */
     template <class T, typename... Params>
-    SkDrawable* allocateDrawable(Params&&... params) {
+    T* allocateDrawable(Params&&... params) {
         return allocator.create<T>(std::forward<Params>(params)...);
     }
 
@@ -96,6 +93,8 @@
      */
     bool hasVectorDrawables() const { return !mVectorDrawables.empty(); }
 
+    bool hasText() const { return mDisplayList.hasText(); }
+
     /**
      * Attempts to reset and reuse this DisplayList.
      *
@@ -155,7 +154,7 @@
      * cannot relocate.
      */
     std::deque<RenderNodeDrawable> mChildNodes;
-    std::deque<GLFunctorDrawable> mChildFunctors;
+    std::deque<FunctorDrawable*> mChildFunctors;
     std::vector<SkImage*> mMutableImages;
     std::vector<VectorDrawableRoot*> mVectorDrawables;
     std::vector<AnimatedImageDrawable*> mAnimatedImages;
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index d58b59e..e8bf492 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -21,12 +21,15 @@
 #include "SkiaPipeline.h"
 #include "SkiaProfileRenderer.h"
 #include "hwui/Bitmap.h"
+#include "private/hwui/DrawGlInfo.h"
 #include "renderstate/RenderState.h"
 #include "renderthread/EglManager.h"
 #include "renderthread/Frame.h"
 #include "utils/GLUtils.h"
 #include "utils/TraceUtils.h"
 
+#include <GLES3/gl3.h>
+
 #include <GrBackendSurface.h>
 #include <SkBlendMode.h>
 #include <SkImageInfo.h>
@@ -41,7 +44,13 @@
 namespace skiapipeline {
 
 SkiaOpenGLPipeline::SkiaOpenGLPipeline(RenderThread& thread)
-        : SkiaPipeline(thread), mEglManager(thread.eglManager()) {}
+        : SkiaPipeline(thread), mEglManager(thread.eglManager()) {
+    thread.renderState().registerContextCallback(this);
+}
+
+SkiaOpenGLPipeline::~SkiaOpenGLPipeline() {
+    mRenderThread.renderState().removeContextCallback(this);
+}
 
 MakeCurrentResult SkiaOpenGLPipeline::makeCurrent() {
     // TODO: Figure out why this workaround is needed, see b/13913604
@@ -62,21 +71,23 @@
 bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
                               const LightGeometry& lightGeometry,
                               LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds,
-                              bool opaque, bool wideColorGamut, const LightInfo& lightInfo,
+                              bool opaque, const LightInfo& lightInfo,
                               const std::vector<sp<RenderNode>>& renderNodes,
                               FrameInfoVisualizer* profiler) {
     mEglManager.damageFrame(frame, dirty);
 
-    SkColorType colorType;
+    SkColorType colorType = getSurfaceColorType();
     // setup surface for fbo0
     GrGLFramebufferInfo fboInfo;
     fboInfo.fFBOID = 0;
-    if (wideColorGamut) {
+    if (colorType == kRGBA_F16_SkColorType) {
         fboInfo.fFormat = GL_RGBA16F;
-        colorType = kRGBA_F16_SkColorType;
-    } else {
+    } else if (colorType == kN32_SkColorType) {
+        // Note: The default preference of pixel format is RGBA_8888, when other
+        // pixel format is available, we should branch out and do more check.
         fboInfo.fFormat = GL_RGBA8;
-        colorType = kN32_SkColorType;
+    } else {
+        LOG_ALWAYS_FATAL("Unsupported color type.");
     }
 
     GrBackendRenderTarget backendRT(frame.width(), frame.height(), 0, STENCIL_BUFFER_SIZE, fboInfo);
@@ -89,8 +100,7 @@
             nullptr, &props));
 
     SkiaPipeline::updateLighting(lightGeometry, lightInfo);
-    renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, wideColorGamut, contentDrawBounds,
-                surface);
+    renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
     layerUpdateQueue->clear();
 
     // Draw visual debugging features
@@ -132,6 +142,13 @@
     return new DeferredLayerUpdater(mRenderThread.renderState());
 }
 
+void SkiaOpenGLPipeline::onContextDestroyed() {
+    if (mEglSurface != EGL_NO_SURFACE) {
+        mEglManager.destroySurface(mEglSurface);
+        mEglSurface = EGL_NO_SURFACE;
+    }
+}
+
 void SkiaOpenGLPipeline::onStop() {
     if (mEglManager.isCurrent(mEglSurface)) {
         mEglManager.makeCurrent(EGL_NO_SURFACE);
@@ -147,8 +164,7 @@
 
     if (surface) {
         mRenderThread.requireGlContext();
-        const bool wideColorGamut = colorMode == ColorMode::WideColorGamut;
-        mEglSurface = mEglManager.createSurface(surface, wideColorGamut);
+        mEglSurface = mEglManager.createSurface(surface, colorMode);
     }
 
     if (mEglSurface != EGL_NO_SURFACE) {
@@ -168,6 +184,14 @@
     return CC_LIKELY(mEglManager.hasEglContext());
 }
 
+SkColorType SkiaOpenGLPipeline::getSurfaceColorType() const {
+    return mEglManager.getSurfaceColorType();
+}
+
+sk_sp<SkColorSpace> SkiaOpenGLPipeline::getSurfaceColorSpace() {
+    return mEglManager.getSurfaceColorSpace();
+}
+
 void SkiaOpenGLPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) {
     DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
     if (thread.eglManager().hasEglContext()) {
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index 808685a..086a760 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -18,6 +18,8 @@
 
 #include "SkiaPipeline.h"
 
+#include "renderstate/RenderState.h"
+
 namespace android {
 
 class Bitmap;
@@ -25,17 +27,16 @@
 namespace uirenderer {
 namespace skiapipeline {
 
-class SkiaOpenGLPipeline : public SkiaPipeline {
+class SkiaOpenGLPipeline : public SkiaPipeline, public IGpuContextCallback {
 public:
     SkiaOpenGLPipeline(renderthread::RenderThread& thread);
-    virtual ~SkiaOpenGLPipeline() {}
+    virtual ~SkiaOpenGLPipeline();
 
     renderthread::MakeCurrentResult makeCurrent() override;
     renderthread::Frame getFrame() override;
     bool draw(const renderthread::Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
               const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue,
-              const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
-              const LightInfo& lightInfo,
+              const Rect& contentDrawBounds, bool opaque, const LightInfo& lightInfo,
               const std::vector<sp<RenderNode> >& renderNodes,
               FrameInfoVisualizer* profiler) override;
     bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
@@ -46,9 +47,14 @@
     void onStop() override;
     bool isSurfaceReady() override;
     bool isContextReady() override;
+    SkColorType getSurfaceColorType() const override;
+    sk_sp<SkColorSpace> getSurfaceColorSpace() override;
 
     static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);
 
+protected:
+    void onContextDestroyed() override;
+
 private:
     renderthread::EglManager& mEglManager;
     EGLSurface mEglSurface = EGL_NO_SURFACE;
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 988981d..2dfe7c7 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -83,16 +83,15 @@
 
 void SkiaPipeline::renderLayers(const LightGeometry& lightGeometry,
                                 LayerUpdateQueue* layerUpdateQueue, bool opaque,
-                                bool wideColorGamut, const LightInfo& lightInfo) {
+                                const LightInfo& lightInfo) {
     updateLighting(lightGeometry, lightInfo);
     ATRACE_NAME("draw layers");
     renderVectorDrawableCache();
-    renderLayersImpl(*layerUpdateQueue, opaque, wideColorGamut);
+    renderLayersImpl(*layerUpdateQueue, opaque);
     layerUpdateQueue->clear();
 }
 
-void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque,
-                                    bool wideColorGamut) {
+void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque) {
     sk_sp<GrContext> cachedContext;
 
     // Render all layers that need to be updated, in order.
@@ -161,7 +160,7 @@
 }
 
 bool SkiaPipeline::createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
-                                       bool wideColorGamut, ErrorHandler* errorHandler) {
+                                       ErrorHandler* errorHandler) {
     // compute the size of the surface (i.e. texture) to be allocated for this layer
     const int surfaceWidth = ceilf(node->getWidth() / float(LAYER_SIZE)) * LAYER_SIZE;
     const int surfaceHeight = ceilf(node->getHeight() / float(LAYER_SIZE)) * LAYER_SIZE;
@@ -169,12 +168,8 @@
     SkSurface* layer = node->getLayerSurface();
     if (!layer || layer->width() != surfaceWidth || layer->height() != surfaceHeight) {
         SkImageInfo info;
-        if (wideColorGamut) {
-            info = SkImageInfo::Make(surfaceWidth, surfaceHeight, kRGBA_F16_SkColorType,
-                                     kPremul_SkAlphaType);
-        } else {
-            info = SkImageInfo::MakeN32Premul(surfaceWidth, surfaceHeight);
-        }
+        info = SkImageInfo::Make(surfaceWidth, surfaceHeight, getSurfaceColorType(),
+                                 kPremul_SkAlphaType);
         SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
         SkASSERT(mRenderThread.getGrContext() != nullptr);
         node->setLayerSurface(SkSurface::MakeRenderTarget(mRenderThread.getGrContext(),
@@ -205,10 +200,6 @@
     return false;
 }
 
-void SkiaPipeline::destroyLayer(RenderNode* node) {
-    node->setLayerSurface(nullptr);
-}
-
 void SkiaPipeline::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) {
     GrContext* context = thread.getGrContext();
     if (context) {
@@ -321,19 +312,18 @@
 
 void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
                                const std::vector<sp<RenderNode>>& nodes, bool opaque,
-                               bool wideColorGamut, const Rect& contentDrawBounds,
-                               sk_sp<SkSurface> surface) {
+                               const Rect& contentDrawBounds, sk_sp<SkSurface> surface) {
     renderVectorDrawableCache();
 
     // draw all layers up front
-    renderLayersImpl(layers, opaque, wideColorGamut);
+    renderLayersImpl(layers, opaque);
 
     // initialize the canvas for the current frame, that might be a recording canvas if SKP
     // capture is enabled.
     std::unique_ptr<SkPictureRecorder> recorder;
     SkCanvas* canvas = tryCapture(surface.get());
 
-    renderFrameImpl(layers, clip, nodes, opaque, wideColorGamut, contentDrawBounds, canvas);
+    renderFrameImpl(layers, clip, nodes, opaque, contentDrawBounds, canvas);
 
     endCapture(surface.get());
 
@@ -354,13 +344,12 @@
 
 void SkiaPipeline::renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip,
                                    const std::vector<sp<RenderNode>>& nodes, bool opaque,
-                                   bool wideColorGamut, const Rect& contentDrawBounds,
-                                   SkCanvas* canvas) {
+                                   const Rect& contentDrawBounds, SkCanvas* canvas) {
     SkAutoCanvasRestore saver(canvas, true);
     canvas->androidFramework_setDeviceClipRestriction(clip.roundOut());
 
     // STOPSHIP: Revert, temporary workaround to clear always F16 frame buffer for b/74976293
-    if (!opaque || wideColorGamut) {
+    if (!opaque || getSurfaceColorType() == kRGBA_F16_SkColorType) {
         canvas->clear(SK_ColorTRANSPARENT);
     }
 
@@ -493,7 +482,7 @@
     // each time a pixel would have been drawn.
     // Pass true for opaque so we skip the clear - the overdrawCanvas is already zero
     // initialized.
-    renderFrameImpl(layers, clip, nodes, true, false, contentDrawBounds, &overdrawCanvas);
+    renderFrameImpl(layers, clip, nodes, true, contentDrawBounds, &overdrawCanvas);
     sk_sp<SkImage> counts = offscreen->makeImageSnapshot();
 
     // Draw overdraw colors to the canvas.  The color filter will convert counts to colors.
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index 8c9c803..ee9158c 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -42,24 +42,21 @@
     void unpinImages() override;
     void onPrepareTree() override;
 
-    void renderLayers(const LightGeometry& lightGeometry,
-                      LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
-                      const LightInfo& lightInfo) override;
+    void renderLayers(const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue,
+                      bool opaque, const LightInfo& lightInfo) override;
 
     bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
-                             bool wideColorGamut, ErrorHandler* errorHandler) override;
+                             ErrorHandler* errorHandler) override;
 
     void renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
-                     const std::vector<sp<RenderNode>>& nodes, bool opaque, bool wideColorGamut,
+                     const std::vector<sp<RenderNode>>& nodes, bool opaque,
                      const Rect& contentDrawBounds, sk_sp<SkSurface> surface);
 
     std::vector<VectorDrawableRoot*>* getVectorDrawables() { return &mVectorDrawables; }
 
-    static void destroyLayer(RenderNode* node);
-
     static void prepareToDraw(const renderthread::RenderThread& thread, Bitmap* bitmap);
 
-    void renderLayersImpl(const LayerUpdateQueue& layers, bool opaque, bool wideColorGamut);
+    void renderLayersImpl(const LayerUpdateQueue& layers, bool opaque);
 
     static float getLightRadius() {
         if (CC_UNLIKELY(Properties::overrideLightRadius > 0)) {
@@ -112,7 +109,7 @@
 
 private:
     void renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip,
-                         const std::vector<sp<RenderNode>>& nodes, bool opaque, bool wideColorGamut,
+                         const std::vector<sp<RenderNode>>& nodes, bool opaque,
                          const Rect& contentDrawBounds, SkCanvas* canvas);
 
     /**
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 83d7e6a..fac07d7 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -23,6 +23,8 @@
 #include "NinePatchUtils.h"
 #include "RenderNode.h"
 #include "pipeline/skia/AnimatedDrawables.h"
+#include "pipeline/skia/GLFunctorDrawable.h"
+#include "pipeline/skia/VkFunctorDrawable.h"
 
 namespace android {
 namespace uirenderer {
@@ -111,37 +113,25 @@
     // use staging property, since recording on UI thread
     if (renderNode->stagingProperties().isProjectionReceiver()) {
         mDisplayList->mProjectionReceiver = &renderNodeDrawable;
-        // set projectionReceiveIndex so that RenderNode.hasProjectionReceiver returns true
-        mDisplayList->projectionReceiveIndex = mDisplayList->mChildNodes.size() - 1;
     }
 }
 
 void SkiaRecordingCanvas::callDrawGLFunction(Functor* functor,
                                              uirenderer::GlFunctorLifecycleListener* listener) {
-    // Drawable dtor will be invoked when mChildFunctors deque is cleared.
-    mDisplayList->mChildFunctors.emplace_back(functor, listener, asSkCanvas());
-    drawDrawable(&mDisplayList->mChildFunctors.back());
+    FunctorDrawable* functorDrawable;
+    if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
+        functorDrawable = mDisplayList->allocateDrawable<VkFunctorDrawable>(functor, listener,
+                asSkCanvas());
+    } else {
+        functorDrawable = mDisplayList->allocateDrawable<GLFunctorDrawable>(functor, listener,
+                asSkCanvas());
+    }
+    mDisplayList->mChildFunctors.push_back(functorDrawable);
+    drawDrawable(functorDrawable);
 }
 
-class VectorDrawable : public SkDrawable {
-public:
-    VectorDrawable(VectorDrawableRoot* tree)
-            : mRoot(tree)
-            , mBounds(tree->stagingProperties()->getBounds()) {}
-
-protected:
-    virtual SkRect onGetBounds() override { return mBounds; }
-    virtual void onDraw(SkCanvas* canvas) override {
-        mRoot->draw(canvas, mBounds);
-    }
-
-private:
-    sp<VectorDrawableRoot> mRoot;
-    SkRect mBounds;
-};
-
 void SkiaRecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
-    drawDrawable(mDisplayList->allocateDrawable<VectorDrawable>(tree));
+    mRecorder.drawVectorDrawable(tree);
     mDisplayList->mVectorDrawables.push_back(tree);
 }
 
@@ -187,7 +177,7 @@
 void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
     sk_sp<SkColorFilter> colorFilter;
     sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
-    mRecorder.drawImage(image, left, top, filterBitmap(paint, std::move(colorFilter)));
+    mRecorder.drawImage(image, left, top, filterBitmap(paint, std::move(colorFilter)), bitmap.palette());
     // if image->unique() is true, then mRecorder.drawImage failed for some reason. It also means
     // it is not safe to store a raw SkImage pointer, because the image object will be destroyed
     // when this function ends.
@@ -202,7 +192,7 @@
 
     sk_sp<SkColorFilter> colorFilter;
     sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
-    mRecorder.drawImage(image, 0, 0, filterBitmap(paint, std::move(colorFilter)));
+    mRecorder.drawImage(image, 0, 0, filterBitmap(paint, std::move(colorFilter)), bitmap.palette());
     if (!bitmap.isImmutable() && image.get() && !image->unique()) {
         mDisplayList->mMutableImages.push_back(image.get());
     }
@@ -217,7 +207,7 @@
     sk_sp<SkColorFilter> colorFilter;
     sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
     mRecorder.drawImageRect(image, srcRect, dstRect, filterBitmap(paint, std::move(colorFilter)),
-                            SkCanvas::kFast_SrcRectConstraint);
+                            SkCanvas::kFast_SrcRectConstraint, bitmap.palette());
     if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty() &&
         !dstRect.isEmpty()) {
         mDisplayList->mMutableImages.push_back(image.get());
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 611a34c..4ef30fc 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -22,6 +22,7 @@
 #include "SkiaProfileRenderer.h"
 #include "renderstate/RenderState.h"
 #include "renderthread/Frame.h"
+#include "VkFunctorDrawable.h"
 
 #include <SkSurface.h>
 #include <SkTypes.h>
@@ -63,8 +64,7 @@
 bool SkiaVulkanPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
                               const LightGeometry& lightGeometry,
                               LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds,
-                              bool opaque, bool wideColorGamut,
-                              const LightInfo& lightInfo,
+                              bool opaque, const LightInfo& lightInfo,
                               const std::vector<sp<RenderNode>>& renderNodes,
                               FrameInfoVisualizer* profiler) {
     sk_sp<SkSurface> backBuffer = mVkSurface->getBackBufferSurface();
@@ -72,8 +72,7 @@
         return false;
     }
     SkiaPipeline::updateLighting(lightGeometry, lightInfo);
-    renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, wideColorGamut, contentDrawBounds,
-                backBuffer);
+    renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, backBuffer);
     layerUpdateQueue->clear();
 
     // Draw visual debugging features
@@ -124,8 +123,7 @@
     }
 
     if (surface) {
-        // TODO: handle color mode
-        mVkSurface = mVkManager.createSurface(surface);
+        mVkSurface = mVkManager.createSurface(surface, colorMode);
     }
 
     return mVkSurface != nullptr;
@@ -139,10 +137,16 @@
     return CC_LIKELY(mVkManager.hasVkContext());
 }
 
+SkColorType SkiaVulkanPipeline::getSurfaceColorType() const {
+    return mVkManager.getSurfaceColorType();
+}
+
+sk_sp<SkColorSpace> SkiaVulkanPipeline::getSurfaceColorSpace() {
+    return mVkManager.getSurfaceColorSpace();
+}
+
 void SkiaVulkanPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) {
-    // TODO: we currently don't support OpenGL WebView's
-    DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
-    (*functor)(mode, nullptr);
+    VkFunctorDrawable::vkInvokeFunctor(functor);
 }
 
 sk_sp<Bitmap> SkiaVulkanPipeline::allocateHardwareBitmap(renderthread::RenderThread& renderThread,
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index 900b054..6e723a8 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -32,8 +32,7 @@
     renderthread::Frame getFrame() override;
     bool draw(const renderthread::Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
               const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue,
-              const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
-              const LightInfo& lightInfo,
+              const Rect& contentDrawBounds, bool opaque, const LightInfo& lightInfo,
               const std::vector<sp<RenderNode> >& renderNodes,
               FrameInfoVisualizer* profiler) override;
     bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
@@ -44,6 +43,8 @@
     void onStop() override;
     bool isSurfaceReady() override;
     bool isContextReady() override;
+    SkColorType getSurfaceColorType() const override;
+    sk_sp<SkColorSpace> getSurfaceColorSpace() override;
 
     static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);
     static sk_sp<Bitmap> allocateHardwareBitmap(renderthread::RenderThread& thread,
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
new file mode 100644
index 0000000..6486ddb
--- /dev/null
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "VkFunctorDrawable.h"
+#include <private/hwui/DrawGlInfo.h>
+
+#include "renderthread/EglManager.h"
+#include "thread/ThreadBase.h"
+#include "utils/TimeUtils.h"
+#include <thread>
+#include <utils/Color.h>
+#include <utils/Trace.h>
+#include <utils/TraceUtils.h>
+
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES3/gl3.h>
+
+#include <utils/GLUtils.h>
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+static std::mutex sLock{};
+static ThreadBase* sGLDrawThread = nullptr;
+static renderthread::EglManager sEglManager;
+
+// ScopedDrawRequest makes sure a GL thread is started and EGL context is initialized on it.
+class ScopedDrawRequest {
+public:
+    ScopedDrawRequest() { beginDraw(); }
+private:
+    void beginDraw() {
+        std::lock_guard{sLock};
+
+        if (!sGLDrawThread) {
+            sGLDrawThread = new ThreadBase{};
+        }
+
+        if (!sGLDrawThread->isRunning()) {
+            sGLDrawThread->start("GLFunctorThread");
+        }
+
+        if (!sEglManager.hasEglContext()) {
+            sGLDrawThread->queue().runSync([]() {
+                sEglManager.initialize();
+            });
+        }
+    }
+};
+
+void VkFunctorDrawable::vkInvokeFunctor(Functor* functor) {
+    ScopedDrawRequest _drawRequest{};
+    sGLDrawThread->queue().runSync([&]() {
+        EGLDisplay display = sEglManager.eglDisplay();
+        DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
+        if (display != EGL_NO_DISPLAY) {
+            mode = DrawGlInfo::kModeProcess;
+        }
+        (*functor)(mode, nullptr);
+    });
+}
+
+#define FENCE_TIMEOUT 2000000000
+
+void VkFunctorDrawable::onDraw(SkCanvas* canvas) {
+    ATRACE_CALL();
+
+    if (canvas->getGrContext() == nullptr) {
+        SkDEBUGF(("Attempting to draw VkFunctor into an unsupported surface"));
+        return;
+    }
+
+    ScopedDrawRequest _drawRequest{};
+
+    SkImageInfo surfaceInfo = canvas->imageInfo();
+
+    if (!mFrameBuffer.get() || mFBInfo != surfaceInfo) {
+        // Buffer will be used as an OpenGL ES render target.
+        mFrameBuffer = new GraphicBuffer(
+                 //TODO: try to reduce the size of the buffer: possibly by using clip bounds.
+                 static_cast<uint32_t>(surfaceInfo.width()),
+                 static_cast<uint32_t>(surfaceInfo.height()),
+                 ColorTypeToPixelFormat(surfaceInfo.colorType()),
+                 GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER |
+                         GraphicBuffer::USAGE_SW_READ_NEVER | GraphicBuffer::USAGE_HW_RENDER,
+                 std::string("VkFunctorDrawable::onDraw pid [") + std::to_string(getpid()) + "]");
+        status_t error = mFrameBuffer->initCheck();
+        if (error < 0) {
+            ALOGW("VkFunctorDrawable::onDraw() failed in GraphicBuffer.create()");
+            return;
+        }
+
+        mFBInfo = surfaceInfo;
+    }
+
+    //TODO: Synchronization is needed on mFrameBuffer to guarantee that the previous Vulkan
+    //TODO: draw command has completed.
+    //TODO: A simple but inefficient way is to flush and issue a QueueWaitIdle call. See
+    //TODO: GrVkGpu::destroyResources() for example.
+    bool success = sGLDrawThread->queue().runSync([&]() -> bool {
+        ATRACE_FORMAT("WebViewDraw_%dx%d", mFBInfo.width(), mFBInfo.height());
+        EGLDisplay display = sEglManager.eglDisplay();
+        LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY,
+                "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
+                uirenderer::renderthread::EglManager::eglErrorString());
+        // We use an EGLImage to access the content of the GraphicBuffer
+        // The EGL image is later bound to a 2D texture
+        EGLClientBuffer clientBuffer = (EGLClientBuffer)mFrameBuffer->getNativeBuffer();
+        AutoEglImage autoImage(display, clientBuffer);
+        if (autoImage.image == EGL_NO_IMAGE_KHR) {
+            ALOGW("Could not create EGL image, err =%s",
+                  uirenderer::renderthread::EglManager::eglErrorString());
+            return false;
+        }
+
+        AutoSkiaGlTexture glTexture;
+        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
+        GL_CHECKPOINT(MODERATE);
+
+        glBindTexture(GL_TEXTURE_2D, 0);
+
+        DrawGlInfo info;
+        SkMatrix44 mat4(canvas->getTotalMatrix());
+        SkIRect clipBounds = canvas->getDeviceClipBounds();
+
+        info.clipLeft = clipBounds.fLeft;
+        info.clipTop = clipBounds.fTop;
+        info.clipRight = clipBounds.fRight;
+        info.clipBottom = clipBounds.fBottom;
+        info.isLayer = true;
+        info.width = mFBInfo.width();
+        info.height = mFBInfo.height();
+        mat4.asColMajorf(&info.transform[0]);
+
+        glViewport(0, 0, info.width, info.height);
+
+        AutoGLFramebuffer glFb;
+        // Bind texture to the frame buffer.
+        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+                             glTexture.mTexture, 0);
+        if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
+            ALOGE("Failed framebuffer check for created target buffer: %s",
+                    GLUtils::getGLFramebufferError());
+            return false;
+        }
+
+        glDisable(GL_STENCIL_TEST);
+        glDisable(GL_SCISSOR_TEST);
+        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+        glClear(GL_COLOR_BUFFER_BIT);
+
+        (*mFunctor)(DrawGlInfo::kModeDraw, &info);
+
+        EGLSyncKHR glDrawFinishedFence =
+                eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL);
+        LOG_ALWAYS_FATAL_IF(glDrawFinishedFence == EGL_NO_SYNC_KHR,
+                "Could not create sync fence %#x", eglGetError());
+        glFlush();
+        // TODO: export EGLSyncKHR in file descr
+        // TODO: import file desc in Vulkan Semaphore
+        // TODO: instead block the GPU: probably by using external Vulkan semaphore.
+        // Block the CPU until the glFlush finish.
+        EGLint waitStatus = eglClientWaitSyncKHR(display, glDrawFinishedFence, 0,
+                FENCE_TIMEOUT);
+        LOG_ALWAYS_FATAL_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR,
+                            "Failed to wait for the fence %#x", eglGetError());
+        eglDestroySyncKHR(display, glDrawFinishedFence);
+        return true;
+    });
+
+    if (!success) {
+        return;
+    }
+
+    SkPaint paint;
+    paint.setBlendMode(SkBlendMode::kSrcOver);
+    canvas->save();
+    // The size of the image matches the size of the canvas. We've used the matrix already, while
+    // drawing into the offscreen surface, so we need to reset it here.
+    canvas->resetMatrix();
+
+    auto functorImage = SkImage::MakeFromAHardwareBuffer(
+        reinterpret_cast<AHardwareBuffer*>(mFrameBuffer.get()), kPremul_SkAlphaType,
+        nullptr, kBottomLeft_GrSurfaceOrigin);
+    canvas->drawImage(functorImage, 0, 0, &paint);
+    canvas->restore();
+}
+
+VkFunctorDrawable::~VkFunctorDrawable() {
+    if (mListener.get() != nullptr) {
+        ScopedDrawRequest _drawRequest{};
+        sGLDrawThread->queue().runSync([&]() {
+             mListener->onGlFunctorReleased(mFunctor);
+        });
+    }
+}
+
+void VkFunctorDrawable::syncFunctor() const {
+    ScopedDrawRequest _drawRequest{};
+    sGLDrawThread->queue().runSync([&]() {
+         (*mFunctor)(DrawGlInfo::kModeSync, nullptr);
+    });
+}
+
+};  // namespace skiapipeline
+};  // namespace uirenderer
+};  // namespace android
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.h b/libs/hwui/pipeline/skia/VkFunctorDrawable.h
new file mode 100644
index 0000000..e37f6fb
--- /dev/null
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "FunctorDrawable.h"
+
+#include <utils/RefBase.h>
+#include <ui/GraphicBuffer.h>
+
+namespace android {
+namespace uirenderer {
+
+namespace skiapipeline {
+
+/**
+ * This drawable wraps a Vulkan functor enabling it to be recorded into a list
+ * of Skia drawing commands.
+ */
+class VkFunctorDrawable : public FunctorDrawable {
+public:
+    VkFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, SkCanvas* canvas)
+            : FunctorDrawable(functor, listener, canvas) {}
+    virtual ~VkFunctorDrawable();
+
+    void syncFunctor() const override;
+
+    static void vkInvokeFunctor(Functor* functor);
+
+protected:
+    virtual void onDraw(SkCanvas* canvas) override;
+
+private:
+
+    // Variables below describe/store temporary offscreen buffer used for Vulkan pipeline.
+    sp<GraphicBuffer> mFrameBuffer;
+    SkImageInfo mFBInfo;
+};
+
+};  // namespace skiapipeline
+};  // namespace uirenderer
+};  // namespace android
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index b524bcb..fad9440 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -14,91 +14,28 @@
  * limitations under the License.
  */
 #include "renderstate/RenderState.h"
-#include <GpuMemoryTracker.h>
-#include "DeferredLayerUpdater.h"
-#include "Snapshot.h"
 
-#include "renderthread/CanvasContext.h"
-#include "renderthread/EglManager.h"
-#include "utils/GLUtils.h"
-
-#include <algorithm>
-
-#include <ui/ColorSpace.h>
+#include "renderthread/RenderThread.h"
+#include "GpuMemoryTracker.h"
 
 namespace android {
 namespace uirenderer {
 
-RenderState::RenderState(renderthread::RenderThread& thread)
-        : mRenderThread(thread), mViewportWidth(0), mViewportHeight(0), mFramebuffer(0) {
+RenderState::RenderState(renderthread::RenderThread& thread) : mRenderThread(thread) {
     mThreadId = pthread_self();
 }
 
-RenderState::~RenderState() {
-}
-
 void RenderState::onContextCreated() {
     GpuMemoryTracker::onGpuContextCreated();
 }
 
 void RenderState::onContextDestroyed() {
-    destroyLayersInUpdater();
+    for(auto callback : mContextCallbacks) {
+        callback->onContextDestroyed();
+    }
     GpuMemoryTracker::onGpuContextDestroyed();
 }
 
-GrContext* RenderState::getGrContext() const {
-    return mRenderThread.getGrContext();
-}
-
-void RenderState::onBitmapDestroyed(uint32_t pixelRefId) {
-    // DEAD CODE
-}
-
-void RenderState::setViewport(GLsizei width, GLsizei height) {
-    mViewportWidth = width;
-    mViewportHeight = height;
-    glViewport(0, 0, mViewportWidth, mViewportHeight);
-}
-
-void RenderState::getViewport(GLsizei* outWidth, GLsizei* outHeight) {
-    *outWidth = mViewportWidth;
-    *outHeight = mViewportHeight;
-}
-
-void RenderState::bindFramebuffer(GLuint fbo) {
-    if (mFramebuffer != fbo) {
-        mFramebuffer = fbo;
-        glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
-    }
-}
-
-GLuint RenderState::createFramebuffer() {
-    GLuint ret;
-    glGenFramebuffers(1, &ret);
-    return ret;
-}
-
-void RenderState::deleteFramebuffer(GLuint fbo) {
-    if (mFramebuffer == fbo) {
-        // GL defines that deleting the currently bound FBO rebinds FBO 0.
-        // Reflect this in our cached value.
-        mFramebuffer = 0;
-    }
-    glDeleteFramebuffers(1, &fbo);
-}
-
-void RenderState::debugOverdraw(bool enable, bool clear) {
-    // DEAD CODE
-}
-
-static void destroyLayerInUpdater(DeferredLayerUpdater* layerUpdater) {
-    layerUpdater->destroyLayer();
-}
-
-void RenderState::destroyLayersInUpdater() {
-    std::for_each(mActiveLayerUpdaters.begin(), mActiveLayerUpdaters.end(), destroyLayerInUpdater);
-}
-
 void RenderState::postDecStrong(VirtualLightRefBase* object) {
     if (pthread_equal(mThreadId, pthread_self())) {
         object->decStrong(nullptr);
@@ -111,13 +48,5 @@
 // Render
 ///////////////////////////////////////////////////////////////////////////////
 
-void RenderState::dump() {
-    // DEAD CODE
-}
-
-renderthread::RenderThread& RenderState::getRenderThread() {
-    return mRenderThread;
-}
-
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h
index f39aa4b..ff5d02f 100644
--- a/libs/hwui/renderstate/RenderState.h
+++ b/libs/hwui/renderstate/RenderState.h
@@ -18,29 +18,26 @@
 
 #include "utils/Macros.h"
 
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#include <private/hwui/DrawGlInfo.h>
-#include <ui/Region.h>
-#include <utils/Functor.h>
-#include <utils/Mutex.h>
 #include <utils/RefBase.h>
 #include <set>
 
-class GrContext;
-
 namespace android {
 namespace uirenderer {
 
 class Layer;
-class DeferredLayerUpdater;
 
 namespace renderthread {
 class CacheManager;
-class CanvasContext;
 class RenderThread;
 }
 
+class IGpuContextCallback {
+public:
+    virtual void onContextDestroyed() = 0;
+protected:
+    virtual ~IGpuContextCallback() {}
+};
+
 // wrapper of Caches for users to migrate to.
 class RenderState {
     PREVENT_COPY_AND_ASSIGN(RenderState);
@@ -48,66 +45,30 @@
     friend class renderthread::CacheManager;
 
 public:
-    void onContextCreated();
-    void onContextDestroyed();
-
-    void onBitmapDestroyed(uint32_t pixelRefId);
-
-    void setViewport(GLsizei width, GLsizei height);
-    void getViewport(GLsizei* outWidth, GLsizei* outHeight);
-
-    void bindFramebuffer(GLuint fbo);
-    GLuint getFramebuffer() { return mFramebuffer; }
-    GLuint createFramebuffer();
-    void deleteFramebuffer(GLuint fbo);
-
-    void debugOverdraw(bool enable, bool clear);
+    void registerContextCallback(IGpuContextCallback* cb) { mContextCallbacks.insert(cb); }
+    void removeContextCallback(IGpuContextCallback* cb) { mContextCallbacks.erase(cb); }
 
     void registerLayer(Layer* layer) { mActiveLayers.insert(layer); }
     void unregisterLayer(Layer* layer) { mActiveLayers.erase(layer); }
 
-    void registerCanvasContext(renderthread::CanvasContext* context) {
-        mRegisteredContexts.insert(context);
-    }
-
-    void unregisterCanvasContext(renderthread::CanvasContext* context) {
-        mRegisteredContexts.erase(context);
-    }
-
-    void registerDeferredLayerUpdater(DeferredLayerUpdater* layerUpdater) {
-        mActiveLayerUpdaters.insert(layerUpdater);
-    }
-
-    void unregisterDeferredLayerUpdater(DeferredLayerUpdater* layerUpdater) {
-        mActiveLayerUpdaters.erase(layerUpdater);
-    }
-
     // TODO: This system is a little clunky feeling, this could use some
     // more thinking...
     void postDecStrong(VirtualLightRefBase* object);
 
-    GrContext* getGrContext() const;
-
-    void dump();
-
-    renderthread::RenderThread& getRenderThread();
+    renderthread::RenderThread& getRenderThread() const { return mRenderThread; }
 
 private:
-    void destroyLayersInUpdater();
-
     explicit RenderState(renderthread::RenderThread& thread);
-    ~RenderState();
+    ~RenderState() {}
+
+    // Context notifications are only to be triggered by renderthread::RenderThread
+    void onContextCreated();
+    void onContextDestroyed();
+
+    std::set<IGpuContextCallback*> mContextCallbacks;
+    std::set<Layer*> mActiveLayers;
 
     renderthread::RenderThread& mRenderThread;
-
-    std::set<Layer*> mActiveLayers;
-    std::set<DeferredLayerUpdater*> mActiveLayerUpdaters;
-    std::set<renderthread::CanvasContext*> mRegisteredContexts;
-
-    GLsizei mViewportWidth;
-    GLsizei mViewportHeight;
-    GLuint mFramebuffer;
-
     pthread_t mThreadId;
 };
 
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 727cef3..c8c394a 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -27,7 +27,6 @@
 #include "pipeline/skia/SkiaOpenGLPipeline.h"
 #include "pipeline/skia/SkiaPipeline.h"
 #include "pipeline/skia/SkiaVulkanPipeline.h"
-#include "renderstate/RenderState.h"
 #include "utils/GLUtils.h"
 #include "utils/TimeUtils.h"
 #include "../Properties.h"
@@ -76,10 +75,6 @@
     return nullptr;
 }
 
-void CanvasContext::destroyLayer(RenderNode* node) {
-    skiapipeline::SkiaPipeline::destroyLayer(node);
-}
-
 void CanvasContext::invokeFunctor(const RenderThread& thread, Functor* functor) {
     ATRACE_CALL();
     auto renderType = Properties::getRenderPipelineType();
@@ -113,13 +108,11 @@
         , mRenderPipeline(std::move(renderPipeline)) {
     rootRenderNode->makeRoot();
     mRenderNodes.emplace_back(rootRenderNode);
-    mRenderThread.renderState().registerCanvasContext(this);
     mProfiler.setDensity(mRenderThread.mainDisplayInfo().density);
 }
 
 CanvasContext::~CanvasContext() {
     destroy();
-    mRenderThread.renderState().unregisterCanvasContext(this);
     for (auto& node : mRenderNodes) {
         node->clearRoot();
     }
@@ -151,7 +144,8 @@
 
     mNativeSurface = std::move(surface);
 
-    ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::Srgb;
+    // TODO(b/111436479) Introduce a way for app to specify DisplayColorGamut mode.
+    ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::Legacy;
     bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode);
 
     mFrameNumber = -1;
@@ -416,7 +410,7 @@
     SkRect windowDirty = computeDirtyRect(frame, &dirty);
 
     bool drew = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry, &mLayerUpdateQueue,
-                                      mContentDrawBounds, mOpaque, mWideColorGamut, mLightInfo,
+                                      mContentDrawBounds, mOpaque, mLightInfo,
                                       mRenderNodes, &(profiler()));
 
     int64_t frameCompleteNr = mFrameCompleteCallbacks.size() ? getFrameNumber() : -1;
@@ -555,8 +549,7 @@
     // purposes when the frame is actually drawn
     node->setPropertyFieldsDirty(RenderNode::GENERIC);
 
-    mRenderPipeline->renderLayers(mLightGeometry, &mLayerUpdateQueue, mOpaque, mWideColorGamut,
-                                  mLightInfo);
+    mRenderPipeline->renderLayers(mLightGeometry, &mLayerUpdateQueue, mOpaque, mLightInfo);
 
     node->incStrong(nullptr);
     mPrefetchedLayers.insert(node);
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 02ee72f..2307ee4 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -75,8 +75,7 @@
      */
     bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& dmgAccumulator,
                              ErrorHandler* errorHandler) {
-        return mRenderPipeline->createOrUpdateLayer(node, dmgAccumulator, mWideColorGamut,
-                errorHandler);
+        return mRenderPipeline->createOrUpdateLayer(node, dmgAccumulator, errorHandler);
     }
 
     /**
@@ -97,12 +96,6 @@
      */
     void unpinImages() { mRenderPipeline->unpinImages(); }
 
-    /**
-     * Destroy any layers that have been attached to the provided RenderNode removing
-     * any state that may have been set during createOrUpdateLayer().
-     */
-    static void destroyLayer(RenderNode* node);
-
     static void invokeFunctor(const RenderThread& thread, Functor* functor);
 
     static void prepareToDraw(const RenderThread& thread, Bitmap* bitmap);
@@ -189,6 +182,23 @@
         mFrameCompleteCallbacks.push_back(std::move(func));
     }
 
+    void setForceDark(bool enable) {
+        mUseForceDark = enable;
+    }
+
+    bool useForceDark() {
+        // The force-dark override has the highest priority, followed by the disable setting
+        // for the feature as a whole, followed last by whether or not this context has had
+        // force dark set (typically automatically done via UIMode)
+        if (Properties::forceDarkMode) {
+            return true;
+        }
+        if (!Properties::enableForceDarkSupport) {
+            return false;
+        }
+        return mUseForceDark;
+    }
+
 private:
     CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
                   IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline);
@@ -235,6 +245,7 @@
 
     bool mOpaque;
     bool mWideColorGamut = false;
+    bool mUseForceDark = false;
     LightInfo mLightInfo;
     LightGeometry mLightGeometry = {{0, 0, 0}, 0};
 
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 5f8d7ad..0cb23e5 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -20,13 +20,14 @@
 #include <log/log.h>
 #include <private/gui/SyncFeatures.h>
 #include <utils/Trace.h>
+#include "utils/Color.h"
 #include "utils/StringUtils.h"
 
-#include "DeviceInfo.h"
 #include "Frame.h"
 #include "Properties.h"
 
 #include <EGL/eglext.h>
+#include <GLES/gl.h>
 
 #include <string>
 #include <vector>
@@ -75,6 +76,7 @@
     bool pixelFormatFloat = false;
     bool glColorSpace = false;
     bool scRGB = false;
+    bool displayP3 = false;
     bool contextPriority = false;
     bool surfacelessContext = false;
 } EglExtensions;
@@ -124,7 +126,17 @@
     createContext();
     createPBufferSurface();
     makeCurrent(mPBufferSurface, nullptr, /* force */ true);
-    DeviceInfo::initialize();
+
+    mSurfaceColorGamut = DataSpaceToColorGamut(
+        static_cast<android_dataspace>(DeviceInfo::get()->getTargetDataSpace()));
+
+    LOG_ALWAYS_FATAL_IF(mSurfaceColorGamut == SkColorSpace::kDCIP3_D65_Gamut &&
+                        !EglExtensions.displayP3, "EGL doesn't support Display P3.");
+
+    mSurfaceColorType = PixelFormatToColorType(
+        static_cast<android_pixel_format>(DeviceInfo::get()->getTargetPixelFormat()));
+    mSurfaceColorSpace = DataSpaceToColorSpace(
+        static_cast<android_dataspace>(DeviceInfo::get()->getTargetDataSpace()));
 }
 
 void EglManager::initExtensions() {
@@ -148,6 +160,7 @@
 #else
     EglExtensions.scRGB = extensions.has("EGL_EXT_gl_colorspace_scrgb");
 #endif
+    EglExtensions.displayP3 = extensions.has("EGL_EXT_gl_colorspace_display_p3");
     EglExtensions.contextPriority = extensions.has("EGL_IMG_context_priority");
     EglExtensions.surfacelessContext = extensions.has("EGL_KHR_surfaceless_context");
 }
@@ -160,6 +173,10 @@
     ALOGD("Swap behavior %d", static_cast<int>(mSwapBehavior));
     EGLint swapBehavior =
             (mSwapBehavior == SwapBehavior::Preserved) ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
+
+    // Note: The default pixel format is RGBA_8888, when other formats are
+    // available, we should check the target pixel format and configure the
+    // attributes list properly.
     EGLint attribs[] = {EGL_RENDERABLE_TYPE,
                         EGL_OPENGL_ES2_BIT,
                         EGL_RED_SIZE,
@@ -255,11 +272,12 @@
     }
 }
 
-EGLSurface EglManager::createSurface(EGLNativeWindowType window, bool wideColorGamut) {
+EGLSurface EglManager::createSurface(EGLNativeWindowType window, ColorMode colorMode) {
     LOG_ALWAYS_FATAL_IF(!hasEglContext(), "Not initialized");
 
-    wideColorGamut = wideColorGamut && EglExtensions.glColorSpace && EglExtensions.scRGB &&
-                     EglExtensions.pixelFormatFloat && EglExtensions.noConfigContext;
+    bool wideColorGamut = colorMode == ColorMode::WideColorGamut && EglExtensions.glColorSpace &&
+                          EglExtensions.scRGB && EglExtensions.pixelFormatFloat &&
+                          EglExtensions.noConfigContext;
 
     // The color space we want to use depends on whether linear blending is turned
     // on and whether the app has requested wide color gamut rendering. When wide
@@ -269,9 +287,9 @@
     // When wide gamut rendering is off:
     // - Blending is done by default in gamma space, which requires using a
     //   linear EGL color space (the GPU uses the color values as is)
-    // - If linear blending is on, we must use the sRGB EGL color space (the
-    //   GPU will perform sRGB to linear and linear to SRGB conversions before
-    //   and after blending)
+    // - If linear blending is on, we must use the non-linear EGL color space
+    //   (the GPU will perform sRGB to linear and linear to SRGB conversions
+    //   before and after blending)
     //
     // When wide gamut rendering is on we cannot rely on the GPU performing
     // linear blending for us. We use two different color spaces to tag the
@@ -279,7 +297,7 @@
     // - Gamma blending (default) requires the use of the scRGB-nl color space
     // - Linear blending requires the use of the scRGB color space
 
-    // Not all Android targets support the EGL_GL_COLOR_SPACE_KHR extension
+    // Not all Android targets support the EGL_GL_COLORSPACE_KHR extension
     // We insert to placeholders to set EGL_GL_COLORSPACE_KHR and its value.
     // According to section 3.4.1 of the EGL specification, the attributes
     // list is considered empty if the first entry is EGL_NONE
@@ -291,13 +309,21 @@
         if (wideColorGamut) {
             attribs[1] = EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT;
         } else {
-            attribs[1] = EGL_GL_COLORSPACE_SRGB_KHR;
+            if (mSurfaceColorGamut == SkColorSpace::kDCIP3_D65_Gamut) {
+                attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_EXT;
+            } else {
+                attribs[1] = EGL_GL_COLORSPACE_SRGB_KHR;
+            }
         }
 #else
         if (wideColorGamut) {
             attribs[1] = EGL_GL_COLORSPACE_SCRGB_EXT;
         } else {
-            attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR;
+            if (mSurfaceColorGamut == SkColorSpace::kDCIP3_D65_Gamut) {
+                attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_EXT;
+            } else {
+                attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR;
+            }
         }
 #endif
     }
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index 507673a..e97228c 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -18,11 +18,13 @@
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
+#include <SkImageInfo.h>
 #include <SkRect.h>
 #include <cutils/compiler.h>
 #include <ui/Fence.h>
 #include <ui/GraphicBuffer.h>
 #include <utils/StrongPointer.h>
+#include "IRenderPipeline.h"
 
 namespace android {
 namespace uirenderer {
@@ -45,7 +47,7 @@
 
     bool hasEglContext();
 
-    EGLSurface createSurface(EGLNativeWindowType window, bool wideColorGamut);
+    EGLSurface createSurface(EGLNativeWindowType window, ColorMode colorMode);
     void destroySurface(EGLSurface surface);
 
     void destroy();
@@ -76,6 +78,9 @@
     // Depending on installed extensions, the result is either Android native fence or EGL fence.
     status_t createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence, sp<Fence>& nativeFence);
 
+    SkColorType getSurfaceColorType() const { return mSurfaceColorType; }
+    sk_sp<SkColorSpace> getSurfaceColorSpace() { return mSurfaceColorSpace; }
+
 private:
 
     void initExtensions();
@@ -89,8 +94,10 @@
     EGLConfig mEglConfigWideGamut;
     EGLContext mEglContext;
     EGLSurface mPBufferSurface;
-
     EGLSurface mCurrentSurface;
+    SkColorSpace::Gamut mSurfaceColorGamut;
+    SkColorType mSurfaceColorType;
+    sk_sp<SkColorSpace> mSurfaceColorSpace;
 
     enum class SwapBehavior {
         Discard,
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index b7b7853..0297c9c 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -16,11 +16,12 @@
 
 #pragma once
 
+#include "DamageAccumulator.h"
 #include "FrameInfoVisualizer.h"
 #include "LayerUpdateQueue.h"
+#include "Lighting.h"
 #include "SwapBehavior.h"
 #include "hwui/Bitmap.h"
-#include "thread/TaskManager.h"
 
 #include <SkRect.h>
 #include <utils/RefBase.h>
@@ -35,13 +36,25 @@
 
 class DeferredLayerUpdater;
 class ErrorHandler;
+class TaskManager;
 
 namespace renderthread {
 
 enum class MakeCurrentResult { AlreadyCurrent, Failed, Succeeded };
 
 enum class ColorMode {
-    Srgb,
+    // Legacy means HWUI will produce buffer with whatever platform prefers
+    // HWUI to produce, however, HWUI doesn't accurately convert color from
+    // source color space to destination color space, instead HWUI will take
+    // the pixel value directly and interpret it destination color space.
+    Legacy,
+    // DisplayColorGamut means HWUI will produce buffer with whatever platform
+    // prefers HWUI to produce and accurately convert color from source color
+    // space to destination color space.
+    DisplayColorGamut,
+    // WideColorGamut means HWUI would support rendering scRGB non-linear into
+    // a signed buffer with enough range to support the wide color gamut of the
+    // display.
     WideColorGamut,
     // Hdr
 };
@@ -55,7 +68,7 @@
     virtual bool draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
                       const LightGeometry& lightGeometry,
                       LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds,
-                      bool opaque, bool wideColorGamut, const LightInfo& lightInfo,
+                      bool opaque, const LightInfo& lightInfo,
                       const std::vector<sp<RenderNode>>& renderNodes,
                       FrameInfoVisualizer* profiler) = 0;
     virtual bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
@@ -67,15 +80,17 @@
     virtual bool isContextReady() = 0;
     virtual void onDestroyHardwareResources() = 0;
     virtual void renderLayers(const LightGeometry& lightGeometry,
-                              LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
+                              LayerUpdateQueue* layerUpdateQueue, bool opaque,
                               const LightInfo& lightInfo) = 0;
     virtual TaskManager* getTaskManager() = 0;
     virtual bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
-                                     bool wideColorGamut, ErrorHandler* errorHandler) = 0;
+                                     ErrorHandler* errorHandler) = 0;
     virtual bool pinImages(std::vector<SkImage*>& mutableImages) = 0;
     virtual bool pinImages(LsaVector<sk_sp<Bitmap>>& images) = 0;
     virtual void unpinImages() = 0;
     virtual void onPrepareTree() = 0;
+    virtual SkColorType getSurfaceColorType() const = 0;
+    virtual sk_sp<SkColorSpace> getSurfaceColorSpace() = 0;
 
     virtual ~IRenderPipeline() {}
 };
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 7a5348a..54219b5 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -298,6 +298,12 @@
     });
 }
 
+void RenderProxy::setForceDark(bool enable) {
+    mRenderThread.queue().post([this, enable]() {
+        mContext->setForceDark(enable);
+    });
+}
+
 int RenderProxy::copySurfaceInto(sp<Surface>& surface, int left, int top, int right, int bottom,
                                  SkBitmap* bitmap) {
     auto& thread = RenderThread::getInstance();
@@ -345,13 +351,6 @@
     }
 }
 
-void RenderProxy::onBitmapDestroyed(uint32_t pixelRefId) {
-    if (!RenderThread::hasInstance()) return;
-    RenderThread& thread = RenderThread::getInstance();
-    thread.queue().post(
-            [&thread, pixelRefId]() { thread.renderState().onBitmapDestroyed(pixelRefId); });
-}
-
 void RenderProxy::disableVsync() {
     Properties::disableVsync = true;
 }
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 969ad00..d29fcc4 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -119,7 +119,7 @@
 
     ANDROID_API void addFrameMetricsObserver(FrameMetricsObserver* observer);
     ANDROID_API void removeFrameMetricsObserver(FrameMetricsObserver* observer);
-    ANDROID_API long getDroppedFrameReportCount();
+    ANDROID_API void setForceDark(bool enable);
 
     ANDROID_API static int copySurfaceInto(sp<Surface>& surface, int left, int top, int right,
                                            int bottom, SkBitmap* bitmap);
@@ -127,8 +127,6 @@
 
     static int copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap);
 
-    static void onBitmapDestroyed(uint32_t pixelRefId);
-
     ANDROID_API static void disableVsync();
 
     static void repackVectorDrawableAtlas();
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 7258a0a..207673c1 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -162,7 +162,7 @@
 }
 
 void RenderThread::initThreadLocals() {
-    mDisplayInfo = DeviceInfo::queryDisplayInfo();
+    mDisplayInfo = DeviceInfo::get()->displayInfo();
     nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1000000000 / mDisplayInfo.fps);
     mTimeLord.setFrameInterval(frameIntervalNanos);
     initializeDisplayEventReceiver();
@@ -177,7 +177,6 @@
         return;
     }
     mEglManager->initialize();
-    renderState().onContextCreated();
 
 #ifdef HWUI_GLES_WRAP_ENABLED
     debug::GlesDriver* driver = debug::GlesDriver::get();
@@ -201,7 +200,6 @@
 void RenderThread::destroyGlContext() {
     if (mEglManager->hasEglContext()) {
         setGrContext(nullptr);
-        renderState().onContextDestroyed();
         mEglManager->destroy();
     }
 }
@@ -243,9 +241,14 @@
 void RenderThread::setGrContext(sk_sp<GrContext> context) {
     mCacheManager->reset(context);
     if (mGrContext) {
+        mRenderState->onContextDestroyed();
         mGrContext->releaseResourcesAndAbandonContext();
     }
     mGrContext = std::move(context);
+    if (mGrContext) {
+        mRenderState->onContextCreated();
+        DeviceInfo::setMaxTextureSize(mGrContext->maxRenderTargetSize());
+    }
 }
 
 int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 038e13c..83e9db3 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -16,7 +16,8 @@
 
 #include "VulkanManager.h"
 
-#include "DeviceInfo.h"
+#include <private/gui/SyncFeatures.h>
+
 #include "Properties.h"
 #include "RenderThread.h"
 #include "renderstate/RenderState.h"
@@ -40,9 +41,12 @@
 VulkanManager::VulkanManager(RenderThread& thread) : mRenderThread(thread) {}
 
 void VulkanManager::destroy() {
-    mRenderThread.renderState().onContextDestroyed();
     mRenderThread.setGrContext(nullptr);
 
+    // We don't need to explicitly free the command buffer since it automatically gets freed when we
+    // delete the VkCommandPool below.
+    mDummyCB = VK_NULL_HANDLE;
+
     if (VK_NULL_HANDLE != mCommandPool) {
         mDestroyCommandPool(mDevice, mCommandPool, nullptr);
         mCommandPool = VK_NULL_HANDLE;
@@ -228,6 +232,11 @@
     grExtensions.init(getProc, mInstance, mPhysicalDevice, instanceExtensions.size(),
             instanceExtensions.data(), deviceExtensions.size(), deviceExtensions.data());
 
+    if (!grExtensions.hasExtension(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, 1)) {
+        this->destroy();
+        return false;
+    }
+
     memset(&features, 0, sizeof(VkPhysicalDeviceFeatures2));
     features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
     features.pNext = nullptr;
@@ -315,6 +324,8 @@
     GET_DEV_PROC(DeviceWaitIdle);
     GET_DEV_PROC(CreateSemaphore);
     GET_DEV_PROC(DestroySemaphore);
+    GET_DEV_PROC(ImportSemaphoreFdKHR);
+    GET_DEV_PROC(GetSemaphoreFdKHR);
     GET_DEV_PROC(CreateFence);
     GET_DEV_PROC(DestroyFence);
     GET_DEV_PROC(WaitForFences);
@@ -386,6 +397,14 @@
                 &mCommandPool);
         SkASSERT(VK_SUCCESS == res);
     }
+    LOG_ALWAYS_FATAL_IF(mCommandPool == VK_NULL_HANDLE);
+
+    if (!setupDummyCommandBuffer()) {
+        this->destroy();
+        return;
+    }
+    LOG_ALWAYS_FATAL_IF(mDummyCB == VK_NULL_HANDLE);
+
 
     mGetDeviceQueue(mDevice, mPresentQueueIndex, 0, &mPresentQueue);
 
@@ -399,13 +418,9 @@
 
     free_features_extensions_structs(features);
 
-    DeviceInfo::initialize(mRenderThread.getGrContext()->maxRenderTargetSize());
-
     if (Properties::enablePartialUpdates && Properties::useBufferAge) {
         mSwapBehavior = SwapBehavior::BufferAge;
     }
-
-    mRenderThread.renderState().onContextCreated();
 }
 
 // Returns the next BackbufferInfo to use for the next draw. The function will make sure all
@@ -603,7 +618,8 @@
         VulkanSurface::ImageInfo& imageInfo = surface->mImageInfos[i];
         imageInfo.mSurface = SkSurface::MakeFromBackendRenderTarget(
                 mRenderThread.getGrContext(), backendRT, kTopLeft_GrSurfaceOrigin,
-                kRGBA_8888_SkColorType, nullptr, &props);
+                surface->mColorMode == ColorMode::WideColorGamut ? kRGBA_F16_SkColorType
+                : kRGBA_8888_SkColorType, nullptr, &props);
     }
 
     SkASSERT(mCommandPool != VK_NULL_HANDLE);
@@ -718,24 +734,22 @@
                     ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
                     : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
 
-    // Pick our surface format. For now, just make sure it matches our sRGB request:
-    VkFormat surfaceFormat = VK_FORMAT_UNDEFINED;
+    VkFormat surfaceFormat = VK_FORMAT_R8G8B8A8_UNORM;
     VkColorSpaceKHR colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
-
-    bool wantSRGB = false;
-#ifdef ANDROID_ENABLE_LINEAR_BLENDING
-    wantSRGB = true;
-#endif
+    if (surface->mColorMode == ColorMode::WideColorGamut) {
+        surfaceFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
+        colorSpace = VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT;
+    }
+    bool foundSurfaceFormat = false;
     for (uint32_t i = 0; i < surfaceFormatCount; ++i) {
-        // We are assuming we can get either R8G8B8A8_UNORM or R8G8B8A8_SRGB
-        VkFormat desiredFormat = wantSRGB ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM;
-        if (desiredFormat == surfaceFormats[i].format) {
-            surfaceFormat = surfaceFormats[i].format;
-            colorSpace = surfaceFormats[i].colorSpace;
+        if (surfaceFormat == surfaceFormats[i].format
+                && colorSpace == surfaceFormats[i].colorSpace) {
+            foundSurfaceFormat = true;
+            break;
         }
     }
 
-    if (VK_FORMAT_UNDEFINED == surfaceFormat) {
+    if (!foundSurfaceFormat) {
         return false;
     }
 
@@ -797,14 +811,14 @@
     return true;
 }
 
-VulkanSurface* VulkanManager::createSurface(ANativeWindow* window) {
+VulkanSurface* VulkanManager::createSurface(ANativeWindow* window, ColorMode colorMode) {
     initialize();
 
     if (!window) {
         return nullptr;
     }
 
-    VulkanSurface* surface = new VulkanSurface();
+    VulkanSurface* surface = new VulkanSurface(colorMode);
 
     VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo;
     memset(&surfaceCreateInfo, 0, sizeof(VkAndroidSurfaceCreateInfoKHR));
@@ -982,19 +996,176 @@
     return surface->mCurrentTime - lastUsed;
 }
 
+bool VulkanManager::setupDummyCommandBuffer() {
+    if (mDummyCB != VK_NULL_HANDLE) {
+        return true;
+    }
+
+    VkCommandBufferAllocateInfo commandBuffersInfo;
+    memset(&commandBuffersInfo, 0, sizeof(VkCommandBufferAllocateInfo));
+    commandBuffersInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+    commandBuffersInfo.pNext = nullptr;
+    commandBuffersInfo.commandPool = mCommandPool;
+    commandBuffersInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+    commandBuffersInfo.commandBufferCount = 1;
+
+    VkResult err = mAllocateCommandBuffers(mDevice, &commandBuffersInfo, &mDummyCB);
+    if (err != VK_SUCCESS) {
+        // It is probably unnecessary to set this back to VK_NULL_HANDLE, but we set it anyways to
+        // make sure the driver didn't set a value and then return a failure.
+        mDummyCB = VK_NULL_HANDLE;
+        return false;
+    }
+
+    VkCommandBufferBeginInfo beginInfo;
+    memset(&beginInfo, 0, sizeof(VkCommandBufferBeginInfo));
+    beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+    beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
+
+    mBeginCommandBuffer(mDummyCB, &beginInfo);
+    mEndCommandBuffer(mDummyCB);
+    return true;
+}
+
 status_t VulkanManager::fenceWait(sp<Fence>& fence) {
-    //TODO: Insert a wait on fence command into the Vulkan command buffer.
-    // Block CPU on the fence.
-    status_t err = fence->waitForever("VulkanManager::fenceWait");
-    if (err != NO_ERROR) {
-        ALOGE("VulkanManager::fenceWait: error waiting for fence: %d", err);
-        return err;
+    if (!hasVkContext()) {
+        ALOGE("VulkanManager::fenceWait: VkDevice not initialized");
+        return INVALID_OPERATION;
+    }
+
+    if (SyncFeatures::getInstance().useWaitSync() &&
+        SyncFeatures::getInstance().useNativeFenceSync()) {
+        // Block GPU on the fence.
+        int fenceFd = fence->dup();
+        if (fenceFd == -1) {
+            ALOGE("VulkanManager::fenceWait: error dup'ing fence fd: %d", errno);
+            return -errno;
+        }
+
+        VkSemaphoreCreateInfo semaphoreInfo;
+        semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+        semaphoreInfo.pNext = nullptr;
+        semaphoreInfo.flags = 0;
+        VkSemaphore semaphore;
+        VkResult err = mCreateSemaphore(mDevice, &semaphoreInfo, nullptr, &semaphore);
+        if (VK_SUCCESS != err) {
+            ALOGE("Failed to create import semaphore, err: %d", err);
+            return UNKNOWN_ERROR;
+        }
+        VkImportSemaphoreFdInfoKHR importInfo;
+        importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
+        importInfo.pNext = nullptr;
+        importInfo.semaphore = semaphore;
+        importInfo.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT;
+        importInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
+        importInfo.fd = fenceFd;
+
+        err = mImportSemaphoreFdKHR(mDevice, &importInfo);
+        if (VK_SUCCESS != err) {
+            ALOGE("Failed to import semaphore, err: %d", err);
+            return UNKNOWN_ERROR;
+        }
+
+        LOG_ALWAYS_FATAL_IF(mDummyCB == VK_NULL_HANDLE);
+
+        VkPipelineStageFlags waitDstStageFlags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
+
+        VkSubmitInfo submitInfo;
+        memset(&submitInfo, 0, sizeof(VkSubmitInfo));
+        submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+        submitInfo.waitSemaphoreCount = 1;
+        // Wait to make sure aquire semaphore set above has signaled.
+        submitInfo.pWaitSemaphores = &semaphore;
+        submitInfo.pWaitDstStageMask = &waitDstStageFlags;
+        submitInfo.commandBufferCount = 1;
+        submitInfo.pCommandBuffers = &mDummyCB;
+        submitInfo.signalSemaphoreCount = 0;
+
+        mQueueSubmit(mGraphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
+
+        // On Android when we import a semaphore, it is imported using temporary permanence. That
+        // means as soon as we queue the semaphore for a wait it reverts to its previous permanent
+        // state before importing. This means it will now be in an idle state with no pending
+        // signal or wait operations, so it is safe to immediately delete it.
+        mDestroySemaphore(mDevice, semaphore, nullptr);
+    } else {
+        // Block CPU on the fence.
+        status_t err = fence->waitForever("VulkanManager::fenceWait");
+        if (err != NO_ERROR) {
+            ALOGE("VulkanManager::fenceWait: error waiting for fence: %d", err);
+            return err;
+        }
     }
     return OK;
 }
 
 status_t VulkanManager::createReleaseFence(sp<Fence>& nativeFence) {
-    //TODO: Create a fence that is signaled, when all the pending Vulkan commands are flushed.
+    if (!hasVkContext()) {
+        ALOGE("VulkanManager::createReleaseFence: VkDevice not initialized");
+        return INVALID_OPERATION;
+    }
+
+    if (SyncFeatures::getInstance().useFenceSync()) {
+        ALOGE("VulkanManager::createReleaseFence: Vk backend doesn't support non-native fences");
+        return INVALID_OPERATION;
+    }
+
+    if (!SyncFeatures::getInstance().useNativeFenceSync()) {
+        return OK;
+    }
+
+    VkExportSemaphoreCreateInfo exportInfo;
+    exportInfo.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
+    exportInfo.pNext = nullptr;
+    exportInfo.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
+
+    VkSemaphoreCreateInfo semaphoreInfo;
+    semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+    semaphoreInfo.pNext = &exportInfo;
+    semaphoreInfo.flags = 0;
+    VkSemaphore semaphore;
+    VkResult err = mCreateSemaphore(mDevice, &semaphoreInfo, nullptr, &semaphore);
+    if (VK_SUCCESS != err) {
+        ALOGE("VulkanManager::createReleaseFence: Failed to create semaphore");
+        return INVALID_OPERATION;
+    }
+
+    LOG_ALWAYS_FATAL_IF(mDummyCB == VK_NULL_HANDLE);
+
+    VkSubmitInfo submitInfo;
+    memset(&submitInfo, 0, sizeof(VkSubmitInfo));
+    submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submitInfo.waitSemaphoreCount = 0;
+    submitInfo.pWaitSemaphores = nullptr;
+    submitInfo.pWaitDstStageMask = nullptr;
+    submitInfo.commandBufferCount = 1;
+    submitInfo.pCommandBuffers = &mDummyCB;
+    submitInfo.signalSemaphoreCount = 1;
+    submitInfo.pSignalSemaphores = &semaphore;
+
+    mQueueSubmit(mGraphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
+
+    VkSemaphoreGetFdInfoKHR getFdInfo;
+    getFdInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR;
+    getFdInfo.pNext = nullptr;
+    getFdInfo.semaphore = semaphore;
+    getFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
+
+    int fenceFd = 0;
+
+    err = mGetSemaphoreFdKHR(mDevice, &getFdInfo, &fenceFd);
+    if (VK_SUCCESS != err) {
+        ALOGE("VulkanManager::createReleaseFence: Failed to get semaphore Fd");
+        return INVALID_OPERATION;
+    }
+    nativeFence = new Fence(fenceFd);
+
+    // Exporting a semaphore with copy transference via vkGetSemahporeFdKHR, has the same effect of
+    // destroying the semaphore and creating a new one with the same handle, and the payloads
+    // ownership is move to the Fd we created. Thus the semahpore is in a state that we can delete
+    // it and we don't need to wait on the command buffer we submitted to finish.
+    mDestroySemaphore(mDevice, semaphore, nullptr);
+
     return OK;
 }
 
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index ebc11a5..e54eb6a 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -26,6 +26,7 @@
 #include <ui/Fence.h>
 #include <utils/StrongPointer.h>
 #include <vk/GrVkBackendContext.h>
+#include "IRenderPipeline.h"
 
 class GrVkExtensions;
 
@@ -37,7 +38,7 @@
 
 class VulkanSurface {
 public:
-    VulkanSurface() {}
+    VulkanSurface(ColorMode colorMode) : mColorMode(colorMode) {}
 
     sk_sp<SkSurface> getBackBufferSurface() { return mBackbuffer; }
 
@@ -73,6 +74,7 @@
     VkImage* mImages = nullptr;
     ImageInfo* mImageInfos;
     uint16_t mCurrentTime = 0;
+    ColorMode mColorMode;
 };
 
 // This class contains the shared global Vulkan objects, such as VkInstance, VkDevice and VkQueue,
@@ -90,7 +92,7 @@
 
     // Given a window this creates a new VkSurfaceKHR and VkSwapchain and stores them inside a new
     // VulkanSurface object which is returned.
-    VulkanSurface* createSurface(ANativeWindow* window);
+    VulkanSurface* createSurface(ANativeWindow* window, ColorMode colorMode);
 
     // Destroy the VulkanSurface and all associated vulkan objects.
     void destroySurface(VulkanSurface* surface);
@@ -118,6 +120,10 @@
     // Creates a fence that is signaled, when all the pending Vulkan commands are flushed.
     status_t createReleaseFence(sp<Fence>& nativeFence);
 
+    // TODO(b/115636873): Handle composition preference.
+    SkColorType getSurfaceColorType() const { return SkColorType::kN32_SkColorType; }
+    sk_sp<SkColorSpace> getSurfaceColorSpace() { return SkColorSpace::MakeSRGB(); }
+
 private:
     friend class RenderThread;
 
@@ -135,6 +141,8 @@
 
     VulkanSurface::BackbufferInfo* getAvailableBackbuffer(VulkanSurface* surface);
 
+    bool setupDummyCommandBuffer();
+
     // simple wrapper class that exists only to initialize a pointer to NULL
     template <typename FNPTR_TYPE>
     class VkPtr {
@@ -195,6 +203,8 @@
 
     VkPtr<PFN_vkCreateSemaphore> mCreateSemaphore;
     VkPtr<PFN_vkDestroySemaphore> mDestroySemaphore;
+    VkPtr<PFN_vkImportSemaphoreFdKHR> mImportSemaphoreFdKHR;
+    VkPtr<PFN_vkGetSemaphoreFdKHR> mGetSemaphoreFdKHR;
     VkPtr<PFN_vkCreateFence> mCreateFence;
     VkPtr<PFN_vkDestroyFence> mDestroyFence;
     VkPtr<PFN_vkWaitForFences> mWaitForFences;
@@ -212,6 +222,8 @@
     VkQueue mPresentQueue = VK_NULL_HANDLE;
     VkCommandPool mCommandPool = VK_NULL_HANDLE;
 
+    VkCommandBuffer mDummyCB = VK_NULL_HANDLE;
+
     enum class SwapBehavior {
         Discard,
         BufferAge,
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index 0e6582c..a00b8db 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -16,7 +16,6 @@
 
 #pragma once
 
-#include <DeviceInfo.h>
 #include <DisplayList.h>
 #include <Matrix.h>
 #include <Properties.h>
@@ -25,6 +24,7 @@
 #include <Snapshot.h>
 #include <hwui/Bitmap.h>
 #include <pipeline/skia/SkiaRecordingCanvas.h>
+#include <private/hwui/DrawGlInfo.h>
 #include <renderstate/RenderState.h>
 #include <renderthread/RenderThread.h>
 
@@ -179,12 +179,6 @@
     static sp<RenderNode> createNode(
             int left, int top, int right, int bottom,
             std::function<void(RenderProperties& props, Canvas& canvas)> setup) {
-#if HWUI_NULL_GPU
-        // if RenderNodes are being sync'd/used, device info will be needed, since
-        // DeviceInfo::maxTextureSize() affects layer property
-        DeviceInfo::initialize();
-#endif
-
         sp<RenderNode> node = new RenderNode();
         RenderProperties& props = node->mutateStagingProperties();
         props.setLeftTopRightBottom(left, top, right, bottom);
@@ -202,12 +196,6 @@
     static sp<RenderNode> createNode(
             int left, int top, int right, int bottom,
             std::function<void(RenderProperties& props, RecordingCanvasType& canvas)> setup) {
-#if HWUI_NULL_GPU
-        // if RenderNodes are being sync'd/used, device info will be needed, since
-        // DeviceInfo::maxTextureSize() affects layer property
-        DeviceInfo::initialize();
-#endif
-
         sp<RenderNode> node = new RenderNode();
         RenderProperties& props = node->mutateStagingProperties();
         props.setLeftTopRightBottom(left, top, right, bottom);
@@ -233,11 +221,6 @@
             std::function<void(RenderProperties& props, skiapipeline::SkiaRecordingCanvas& canvas)>
                     setup,
             const char* name = nullptr, skiapipeline::SkiaDisplayList* displayList = nullptr) {
-#if HWUI_NULL_GPU
-        // if RenderNodes are being sync'd/used, device info will be needed, since
-        // DeviceInfo::maxTextureSize() affects layer property
-        DeviceInfo::initialize();
-#endif
         sp<RenderNode> node = new RenderNode();
         if (name) {
             node->setName(name);
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index 48bc8e4..2926ef3 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -537,7 +537,7 @@
     layerUpdateQueue.enqueueLayerWithDamage(child.get(),
                                             android::uirenderer::Rect(LAYER_WIDTH, LAYER_HEIGHT));
     auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
-    pipeline->renderLayersImpl(layerUpdateQueue, true, false);
+    pipeline->renderLayersImpl(layerUpdateQueue, true);
     EXPECT_EQ(1, drawCounter);  // assert index 0 is drawn on the layer
 
     RenderNodeDrawable drawable(parent.get(), surfaceLayer1->getCanvas(), true);
diff --git a/libs/hwui/tests/unit/RenderPropertiesTests.cpp b/libs/hwui/tests/unit/RenderPropertiesTests.cpp
index 85655fc..3e8e057 100644
--- a/libs/hwui/tests/unit/RenderPropertiesTests.cpp
+++ b/libs/hwui/tests/unit/RenderPropertiesTests.cpp
@@ -22,8 +22,6 @@
 using namespace android::uirenderer;
 
 TEST(RenderProperties, layerValidity) {
-    DeviceInfo::initialize();
-
     const int maxTextureSize = DeviceInfo::get()->maxTextureSize();
     ASSERT_LE(2048, maxTextureSize);
     ASSERT_GT(100000, maxTextureSize);
diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
index 6c398ee..415f9e8 100644
--- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
+++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
@@ -20,6 +20,7 @@
 #include "AnimationContext.h"
 #include "DamageAccumulator.h"
 #include "IContextFactory.h"
+#include "pipeline/skia/GLFunctorDrawable.h"
 #include "pipeline/skia/SkiaDisplayList.h"
 #include "renderthread/CanvasContext.h"
 #include "tests/common/TestUtils.h"
@@ -46,7 +47,8 @@
     SkCanvas dummyCanvas;
     RenderNodeDrawable drawable(nullptr, &dummyCanvas);
     skiaDL->mChildNodes.emplace_back(nullptr, &dummyCanvas);
-    skiaDL->mChildFunctors.emplace_back(nullptr, nullptr, &dummyCanvas);
+    GLFunctorDrawable functorDrawable(nullptr, nullptr, &dummyCanvas);
+    skiaDL->mChildFunctors.push_back(&functorDrawable);
     skiaDL->mMutableImages.push_back(nullptr);
     skiaDL->mVectorDrawables.push_back(nullptr);
     skiaDL->mProjectionReceiver = &drawable;
@@ -95,7 +97,8 @@
 
     SkCanvas dummyCanvas;
     TestUtils::MockFunctor functor;
-    skiaDL.mChildFunctors.emplace_back(&functor, nullptr, &dummyCanvas);
+    GLFunctorDrawable functorDrawable(&functor, nullptr, &dummyCanvas);
+    skiaDL.mChildFunctors.push_back(&functorDrawable);
 
     SkRect bounds = SkRect::MakeWH(200, 200);
     VectorDrawableRoot vectorDrawable(new VectorDrawable::Group());
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index a9124d9..680fcb3 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -50,7 +50,7 @@
     auto surface = SkSurface::MakeRasterN32Premul(1, 1);
     surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
-    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
                           surface);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
 }
@@ -83,7 +83,7 @@
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
 
     // drawFrame will crash if "SkiaPipeline::onPrepareTree" did not clean invalid VD pointer
-    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
                           surface);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
 }
@@ -105,11 +105,11 @@
     auto surface = SkSurface::MakeRasterN32Premul(2, 2);
     surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
-    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, false, contentDrawBounds,
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds,
                           surface);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN);
-    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, false, false, contentDrawBounds,
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, false, contentDrawBounds,
                           surface);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned int)SK_ColorTRANSPARENT);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN);
@@ -129,7 +129,7 @@
     auto surface = SkSurface::MakeRasterN32Premul(2, 2);
     surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
-    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, false, contentDrawBounds,
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds,
                           surface);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
     ASSERT_EQ(TestUtils::getColor(surface, 1, 0), SK_ColorBLUE);
@@ -171,7 +171,7 @@
     lightGeometry.center = {0.0f, 0.0f, 0.0f};
     LightInfo lightInfo;
     auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
-    pipeline->renderLayers(lightGeometry, &layerUpdateQueue, opaque, false, lightInfo);
+    pipeline->renderLayers(lightGeometry, &layerUpdateQueue, opaque, lightInfo);
     ASSERT_EQ(TestUtils::getColor(surfaceLayer1, 0, 0), SK_ColorRED);
     ASSERT_EQ(TestUtils::getColor(surfaceLayer2, 0, 0), SK_ColorBLUE);
     ASSERT_EQ(TestUtils::getColor(surfaceLayer2, 0, 1), SK_ColorWHITE);
@@ -202,37 +202,37 @@
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
 
     // Single draw, should be white.
-    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
                           surface);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorWHITE);
 
     // 1 Overdraw, should be blue blended onto white.
     renderNodes.push_back(whiteNode);
-    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
                           surface);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffd0d0ff);
 
     // 2 Overdraw, should be green blended onto white
     renderNodes.push_back(whiteNode);
-    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
                           surface);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffd0ffd0);
 
     // 3 Overdraw, should be pink blended onto white.
     renderNodes.push_back(whiteNode);
-    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
                           surface);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffffc0c0);
 
     // 4 Overdraw, should be red blended onto white.
     renderNodes.push_back(whiteNode);
-    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
                           surface);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffff8080);
 
     // 5 Overdraw, should be red blended onto white.
     renderNodes.push_back(whiteNode);
-    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
                           surface);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffff8080);
 }
@@ -318,7 +318,7 @@
     SkRect dirty = SkRect::MakeWH(800, 600);
     auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
     sk_sp<DeferLayer<DeferTestCanvas>> surface(new DeferLayer<DeferTestCanvas>());
-    pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, false, contentDrawBounds, surface);
+    pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, contentDrawBounds, surface);
     EXPECT_EQ(4, surface->canvas()->mDrawCounter);
 }
 
@@ -348,7 +348,7 @@
     SkRect dirty = SkRect::MakeLTRB(10, 20, 30, 40);
     auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
     sk_sp<DeferLayer<ClippedTestCanvas>> surface(new DeferLayer<ClippedTestCanvas>());
-    pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, false,
+    pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true,
                           SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface);
     EXPECT_EQ(1, surface->canvas()->mDrawCounter);
 }
@@ -378,7 +378,17 @@
     SkRect dirty = SkRect::MakeLTRB(10, 10, 40, 40);
     auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
     sk_sp<DeferLayer<ClipReplaceTestCanvas>> surface(new DeferLayer<ClipReplaceTestCanvas>());
-    pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, false,
+    pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true,
                           SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface);
     EXPECT_EQ(1, surface->canvas()->mDrawCounter);
 }
+
+RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, context_lost) {
+    auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
+    EXPECT_FALSE(pipeline->isSurfaceReady());
+    EXPECT_TRUE(pipeline->setSurface((Surface*)0x01, SwapBehavior::kSwap_default, ColorMode::Legacy));
+    EXPECT_TRUE(pipeline->isSurfaceReady());
+    renderThread.destroyGlContext();
+    EXPECT_FALSE(pipeline->isSurfaceReady());
+}
+
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index a3e7859..9f71e91 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -57,6 +57,65 @@
     return false;
 }
 
+SkColorType PixelFormatToColorType(android_pixel_format pixelFormat) {
+    switch (pixelFormat) {
+        case HAL_PIXEL_FORMAT_RGBA_8888:
+        case HAL_PIXEL_FORMAT_BGRA_8888:
+            return SkColorType::kN32_SkColorType;
+        case HAL_PIXEL_FORMAT_RGBA_FP16:
+            return SkColorType::kRGBA_F16_SkColorType;
+        case HAL_PIXEL_FORMAT_RGBA_1010102:
+            return SkColorType::kRGBA_1010102_SkColorType;
+        default:
+            ALOGW("Unsupported pixel format: %d, return kN32 by default", pixelFormat);
+            return SkColorType::kN32_SkColorType;
+    }
+}
+
+android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType) {
+    switch (colorType) {
+        case kRGBA_8888_SkColorType:
+            return PIXEL_FORMAT_RGBA_8888;
+        case kRGBA_F16_SkColorType:
+            return PIXEL_FORMAT_RGBA_FP16;
+        case kRGB_565_SkColorType:
+            return PIXEL_FORMAT_RGB_565;
+        case kRGB_888x_SkColorType:
+            return PIXEL_FORMAT_RGBX_8888;
+        case kRGBA_1010102_SkColorType:
+            return PIXEL_FORMAT_RGBA_1010102;
+        case kARGB_4444_SkColorType:
+            return PIXEL_FORMAT_RGBA_4444;
+        default:
+            ALOGW("Unsupported colorType: %d, return RGBA_8888 by default", (int)colorType);
+            return PIXEL_FORMAT_RGBA_8888;
+    }
+}
+
+SkColorSpace::Gamut DataSpaceToColorGamut(android_dataspace dataSpace) {
+    switch (dataSpace & HAL_DATASPACE_STANDARD_MASK) {
+        case HAL_DATASPACE_STANDARD_BT709:
+            return SkColorSpace::kSRGB_Gamut;
+        case HAL_DATASPACE_STANDARD_BT2020:
+            return SkColorSpace::kRec2020_Gamut;
+        case HAL_DATASPACE_STANDARD_DCI_P3:
+            return SkColorSpace::kDCIP3_D65_Gamut;
+        case HAL_DATASPACE_STANDARD_ADOBE_RGB:
+            return SkColorSpace::kAdobeRGB_Gamut;
+        case HAL_DATASPACE_STANDARD_UNSPECIFIED:
+        case HAL_DATASPACE_STANDARD_BT601_625:
+        case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED:
+        case HAL_DATASPACE_STANDARD_BT601_525:
+        case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED:
+        case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE:
+        case HAL_DATASPACE_STANDARD_BT470M:
+        case HAL_DATASPACE_STANDARD_FILM:
+        default:
+            ALOGW("Unsupported Gamut: %d, return SRGB gamut by default", dataSpace);
+            return SkColorSpace::kSRGB_Gamut;
+    }
+}
+
 sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) {
 
     SkColorSpace::Gamut gamut;
diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h
index 3c13a54..e935a0d 100644
--- a/libs/hwui/utils/Color.h
+++ b/libs/hwui/utils/Color.h
@@ -18,9 +18,11 @@
 
 #include <math.h>
 #include <system/graphics.h>
+#include <ui/PixelFormat.h>
 
 #include <SkColor.h>
 #include <SkColorSpace.h>
+#include <SkImageInfo.h>
 
 namespace android {
 namespace uirenderer {
@@ -113,6 +115,12 @@
 // returns true for sRGB, gamma 2.2 and Display P3 for instance
 bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace);
 
+SkColorType PixelFormatToColorType(android_pixel_format pixelFormat);
+
+android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType);
+
+SkColorSpace::Gamut DataSpaceToColorGamut(android_dataspace dataSpace);
+
 sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace);
 
 struct Lab {
diff --git a/libs/hwui/utils/GLUtils.cpp b/libs/hwui/utils/GLUtils.cpp
index bf27300..fcd036c 100644
--- a/libs/hwui/utils/GLUtils.cpp
+++ b/libs/hwui/utils/GLUtils.cpp
@@ -59,5 +59,22 @@
 #endif
 }
 
+const char* GLUtils::getGLFramebufferError() {
+    switch (glCheckFramebufferStatus(GL_FRAMEBUFFER)) {
+        case GL_FRAMEBUFFER_COMPLETE:
+            return "GL_FRAMEBUFFER_COMPLETE";
+        case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
+            return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
+        case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
+            return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
+        case GL_FRAMEBUFFER_UNSUPPORTED:
+            return "GL_FRAMEBUFFER_UNSUPPORTED";
+        case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
+            return "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
+        default:
+            return "Unknown error";
+    }
+}
+
 };  // namespace uirenderer
 };  // namespace android
diff --git a/libs/hwui/utils/GLUtils.h b/libs/hwui/utils/GLUtils.h
index debfb5d..ca8810b 100644
--- a/libs/hwui/utils/GLUtils.h
+++ b/libs/hwui/utils/GLUtils.h
@@ -20,6 +20,12 @@
 
 #include <log/log.h>
 
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES3/gl3.h>
+
 namespace android {
 namespace uirenderer {
 
@@ -43,8 +49,53 @@
      */
     static bool dumpGLErrors();
 
+    static const char* getGLFramebufferError();
 };  // class GLUtils
 
+class AutoEglImage {
+public:
+    AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer) : mDisplay(display) {
+        EGLint imageAttrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
+        image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer,
+                                  imageAttrs);
+    }
+
+    ~AutoEglImage() {
+        if (image != EGL_NO_IMAGE_KHR) {
+            eglDestroyImageKHR(mDisplay, image);
+        }
+    }
+
+    EGLImageKHR image = EGL_NO_IMAGE_KHR;
+
+private:
+    EGLDisplay mDisplay = EGL_NO_DISPLAY;
+};
+
+class AutoSkiaGlTexture {
+public:
+    AutoSkiaGlTexture() {
+        glGenTextures(1, &mTexture);
+        glBindTexture(GL_TEXTURE_2D, mTexture);
+    }
+
+    ~AutoSkiaGlTexture() { glDeleteTextures(1, &mTexture); }
+
+    GLuint mTexture = 0;
+};
+
+class AutoGLFramebuffer {
+public:
+    AutoGLFramebuffer() {
+        glGenFramebuffers(1, &mFb);
+        glBindFramebuffer(GL_FRAMEBUFFER, mFb);
+    }
+
+    ~AutoGLFramebuffer() { glDeleteFramebuffers(1, &mFb); }
+
+    GLuint mFb;
+};
+
 } /* namespace uirenderer */
 } /* namespace android */
 
diff --git a/libs/services/include/android/os/StatsLogEventWrapper.h b/libs/services/include/android/os/StatsLogEventWrapper.h
index 255619c..52cb75e 100644
--- a/libs/services/include/android/os/StatsLogEventWrapper.h
+++ b/libs/services/include/android/os/StatsLogEventWrapper.h
@@ -25,6 +25,58 @@
 namespace android {
 namespace os {
 
+/**
+ * A wrapper for a union type to contain multiple types of values.
+ *
+ */
+struct StatsLogValue {
+  // Keep in sync with FieldValue.h
+  enum STATS_LOG_VALUE_TYPE {
+    UNKNOWN = 0,
+    INT = 1,
+    LONG = 2,
+    FLOAT = 3,
+    DOUBLE = 4,
+    STRING = 5,
+    STORAGE = 6
+  };
+
+  StatsLogValue() : type(UNKNOWN) {}
+
+  StatsLogValue(int32_t v) {
+    int_value = v;
+    type = INT;
+  }
+
+  StatsLogValue(int64_t v) {
+    long_value = v;
+    type = LONG;
+  }
+
+  StatsLogValue(float v) {
+    float_value = v;
+    type = FLOAT;
+  }
+
+  StatsLogValue(const std::string& v) {
+    str_value = v;
+    type = STRING;
+  }
+
+  void setType(STATS_LOG_VALUE_TYPE t) { type = t; }
+
+  union {
+    int32_t int_value;
+    int64_t long_value;
+    float float_value;
+    double double_value;
+  };
+  std::string str_value;
+  std::vector<uint8_t> storage_value;
+
+  STATS_LOG_VALUE_TYPE type;
+};
+
 // Represents a parcelable object. Only used to send data from Android OS to statsd.
 class StatsLogEventWrapper : public android::Parcelable {
  public:
@@ -36,8 +88,22 @@
 
   android::status_t readFromParcel(const android::Parcel* in);
 
-  // These are public for ease of conversion.
-  std::vector<uint8_t> bytes;
+  int getTagId() const { return mTagId; }
+
+  int64_t getElapsedRealTimeNs() const { return mElapsedRealTimeNs; }
+
+  int64_t getWallClockTimeNs() const { return mWallClockTimeNs; }
+
+  std::vector<StatsLogValue> getElements() const { return mElements; }
+
+ private:
+  int mTagId;
+
+  int64_t mElapsedRealTimeNs;
+
+  int64_t mWallClockTimeNs;
+
+  std::vector<StatsLogValue> mElements;
 };
 } // Namespace os
 } // Namespace android
diff --git a/libs/services/src/os/StatsLogEventWrapper.cpp b/libs/services/src/os/StatsLogEventWrapper.cpp
index 8b3aa9a..04c4629 100644
--- a/libs/services/src/os/StatsLogEventWrapper.cpp
+++ b/libs/services/src/os/StatsLogEventWrapper.cpp
@@ -32,13 +32,70 @@
 StatsLogEventWrapper::StatsLogEventWrapper(){};
 
 status_t StatsLogEventWrapper::writeToParcel(Parcel* out) const {
-    out->writeByteVector(bytes);
-    return ::android::NO_ERROR;
+  // Implement me if desired. We don't currently use this.
+  ALOGE(
+      "Cannot do c++ StatsLogEventWrapper.writeToParcel(); it is not "
+      "implemented.");
+  (void)out;  // To prevent compile error of unused parameter 'in'
+  return UNKNOWN_ERROR;
 };
 
 status_t StatsLogEventWrapper::readFromParcel(const Parcel* in) {
-    in->readByteVector(&bytes);
-    return ::android::NO_ERROR;
+  status_t res = OK;
+  if (in == NULL) {
+    ALOGE("statsd received parcel argument was NULL.");
+    return BAD_VALUE;
+  }
+  if ((res = in->readInt32(&mTagId)) != OK) {
+    ALOGE("statsd could not read tagId from parcel");
+    return res;
+  }
+  if ((res = in->readInt64(&mElapsedRealTimeNs)) != OK) {
+    ALOGE("statsd could not read elapsed real time from parcel");
+    return res;
+  }
+  if ((res = in->readInt64(&mWallClockTimeNs)) != OK) {
+    ALOGE("statsd could not read wall clock time from parcel");
+    return res;
+  }
+  int dataSize = 0;
+  if ((res = in->readInt32(&dataSize)) != OK) {
+    ALOGE("statsd could not read data size from parcel");
+    return res;
+  }
+  if (mTagId <= 0 || mElapsedRealTimeNs <= 0 || mWallClockTimeNs <= 0 ||
+      dataSize <= 0) {
+    ALOGE("statsd received invalid parcel");
+    return BAD_VALUE;
+  }
+
+  for (int i = 0; i < dataSize; i++) {
+    int type = in->readInt32();
+    switch (type) {
+      case StatsLogValue::INT:
+        mElements.push_back(StatsLogValue(in->readInt32()));
+        break;
+      case StatsLogValue::LONG:
+        mElements.push_back(StatsLogValue(in->readInt64()));
+        break;
+      case StatsLogValue::STRING:
+        mElements.push_back(
+            StatsLogValue(std::string(String8(in->readString16()).string())));
+        break;
+      case StatsLogValue::FLOAT:
+        mElements.push_back(StatsLogValue(in->readFloat()));
+        break;
+      case StatsLogValue::STORAGE:
+        mElements.push_back(StatsLogValue());
+        mElements.back().setType(StatsLogValue::STORAGE);
+        in->readByteVector(&(mElements.back().storage_value));
+        break;
+      default:
+        ALOGE("unrecognized data type: %d", type);
+        return BAD_TYPE;
+    }
+  }
+  return NO_ERROR;
 };
 
 } // Namespace os
diff --git a/location/java/android/location/Address.java b/location/java/android/location/Address.java
index 335ad5e..83f05c2 100644
--- a/location/java/android/location/Address.java
+++ b/location/java/android/location/Address.java
@@ -363,7 +363,7 @@
      * or null if it is unknown.
      *
      * @throws IllegalStateException if this Address has not been assigned
-     * a latitude.
+     * a phone number.
      */
     public String getPhone() {
         return mPhone;
diff --git a/location/java/android/location/CountryDetector.java b/location/java/android/location/CountryDetector.java
index 119d1e0..ae13949 100644
--- a/location/java/android/location/CountryDetector.java
+++ b/location/java/android/location/CountryDetector.java
@@ -21,6 +21,7 @@
 import android.annotation.SystemService;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
+import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.RemoteException;
@@ -88,7 +89,7 @@
      *       create an instance of this class is using the factory
      *       Context.getSystemService.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public CountryDetector(ICountryDetector service) {
         mService = service;
         mListeners = new HashMap<CountryListener, ListenerTransport>();
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 5ad7365..f1325ce 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -375,11 +376,11 @@
 
     @UnsupportedAppUsage
     private int mUsage = USAGE_UNKNOWN;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private int mContentType = CONTENT_TYPE_UNKNOWN;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private int mSource = MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private int mFlags = 0x0;
     private HashSet<String> mTags;
     @UnsupportedAppUsage
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index aaf7dd7..62e58ca 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1656,7 +1656,7 @@
     * @param timestamp a reference to a non-null AudioTimestamp instance allocated
     *        and owned by caller.
     * @return true if a timestamp is available, or false if no timestamp is available.
-    *         If a timestamp if available,
+    *         If a timestamp is available,
     *         the AudioTimestamp instance is filled in with a position in frame units, together
     *         with the estimated time when that frame was presented or is committed to
     *         be presented.
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index d45acdf..1d27c03 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -24,6 +24,7 @@
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
 import android.media.MediaCodecInfo.CodecCapabilities;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -42,6 +43,8 @@
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
 
 /**
  MediaCodec class can be used to access low-level media codecs, i.e. encoder/decoder components.
@@ -3580,8 +3583,19 @@
         native_init();
     }
 
-    @UnsupportedAppUsage
-    private long mNativeContext;
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+    private long mNativeContext = 0;
+    private final Lock mNativeContextLock = new ReentrantLock();
+
+    private final long lockAndGetContext() {
+        mNativeContextLock.lock();
+        return mNativeContext;
+    }
+
+    private final void setAndUnlockContext(long context) {
+        mNativeContext = context;
+        mNativeContextLock.unlock();
+    }
 
     /** @hide */
     public static class MediaImage extends Image {
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index ef312d1..995ebb2 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Range;
@@ -1589,7 +1590,7 @@
         private VideoCapabilities() { }
 
         /** @hide */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public static VideoCapabilities create(
                 MediaFormat info, CodecCapabilities parent) {
             VideoCapabilities caps = new VideoCapabilities();
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index 89827bc..7492aa6 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -1108,12 +1108,9 @@
 
     /**
      * Sets playback rate using {@link PlaybackParams}. The object sets its internal
-     * PlaybackParams to the input, except that the object remembers previous speed
-     * when input speed is zero. This allows the object to resume at previous speed
-     * when play() is called. Calling it before the object is prepared does not change
-     * the object state. After the object is prepared, calling it with zero speed is
-     * equivalent to calling pause(). After the object is prepared, calling it with
-     * non-zero speed is equivalent to calling play().
+     * PlaybackParams to the input. This allows the object to resume at previous speed
+     * when play() is called. Speed of zero is not allowed. Calling it does not change
+     * the object state.
      *
      * @param params the playback params.
      */
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 6ae4d40..84d246f 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -86,6 +86,7 @@
 import java.util.UUID;
 import java.util.Vector;
 import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -253,21 +254,6 @@
             void process() {
                 stayAwake(false);
 
-                // TODO: remove this block when native code allows prepared -> pause
-                // and sends MEDIA_INFO_DATA_SOURCE_START when pipeline is created.
-                if (getState() == PLAYER_STATE_PREPARED) {
-                    final DataSourceDesc dsd;
-                    synchronized (mSrcLock) {
-                        dsd = mCurrentDSD;
-                    }
-                    synchronized (mEventCbLock) {
-                        for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
-                            cb.first.execute(() -> cb.second.onInfo(
-                                    MediaPlayer2Impl.this, dsd, MEDIA_INFO_DATA_SOURCE_START, 0));
-                        }
-                    }
-                }
-
                 _pause();
             }
         });
@@ -285,7 +271,10 @@
         addTask(new Task(CALL_COMPLETED_SKIP_TO_NEXT, false) {
             @Override
             void process() {
-                // TODO: switch to next data source and play
+                if (getState() == PLAYER_STATE_PLAYING) {
+                    pause();
+                }
+                playNextDataSource();
             }
         });
     }
@@ -544,29 +533,11 @@
     private static final int INVOKE_ID_GET_SELECTED_TRACK = 7;
 
     /**
-     * Create a request parcel which can be routed to the native media
-     * player using {@link #invoke(Parcel, Parcel)}. The Parcel
-     * returned has the proper InterfaceToken set. The caller should
-     * not overwrite that token, i.e it can only append data to the
-     * Parcel.
-     *
-     * @return A parcel suitable to hold a request for the native
-     * player.
-     * {@hide}
-     */
-    @Override
-    public Parcel newRequest() {
-        Parcel parcel = Parcel.obtain();
-        return parcel;
-    }
-
-    /**
      * Invoke a generic method on the native player using opaque protocol
      * buffer message for the request and reply. Both payloads' format is a
      * convention between the java caller and the native player.
      *
-     * @param request PlayerMessage for the extension. The
-     * caller must use {@link #newRequest()} to get one.
+     * @param msg PlayerMessage for the extension.
      *
      * @return PlayerMessage with the data returned by the
      * native player.
@@ -590,12 +561,13 @@
         addTask(new Task(CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED, false) {
             @Override
             void process() {
-                synchronized (mEventCbLock) {
-                    for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
-                        cb.first.execute(() -> cb.second.onCommandLabelReached(
-                                MediaPlayer2Impl.this, label));
+                sendEvent(new EventNotifier() {
+                    @Override
+                    public void notify(EventCallback callback) {
+                        callback.onCommandLabelReached(
+                                MediaPlayer2Impl.this, label);
                     }
-                }
+                });
             }
         });
     }
@@ -1013,12 +985,13 @@
         }
 
         if (!hasNextDSD) {
-            synchronized (mEventCbLock) {
-                for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
-                    cb.first.execute(() -> cb.second.onInfo(
-                            MediaPlayer2Impl.this, null, MEDIA_INFO_DATA_SOURCE_LIST_END, 0));
+            sendEvent(new EventNotifier() {
+                @Override
+                public void notify(EventCallback callback) {
+                    callback.onInfo(
+                            MediaPlayer2Impl.this, null, MEDIA_INFO_DATA_SOURCE_LIST_END, 0);
                 }
-            }
+            });
         }
     }
 
@@ -1536,91 +1509,6 @@
     }
 
     /**
-     * Gets the media metadata.
-     *
-     * @param update_only controls whether the full set of available
-     * metadata is returned or just the set that changed since the
-     * last call. See {@see #METADATA_UPDATE_ONLY} and {@see
-     * #METADATA_ALL}.
-     *
-     * @param apply_filter if true only metadata that matches the
-     * filter is returned. See {@see #APPLY_METADATA_FILTER} and {@see
-     * #BYPASS_METADATA_FILTER}.
-     *
-     * @return The metadata, possibly empty. null if an error occured.
-     // FIXME: unhide.
-     * {@hide}
-     */
-    @Override
-    public Metadata getMetadata(final boolean update_only,
-                                final boolean apply_filter) {
-        Parcel reply = Parcel.obtain();
-        Metadata data = new Metadata();
-
-        if (!native_getMetadata(update_only, apply_filter, reply)) {
-            reply.recycle();
-            return null;
-        }
-
-        // Metadata takes over the parcel, don't recycle it unless
-        // there is an error.
-        if (!data.parse(reply)) {
-            reply.recycle();
-            return null;
-        }
-        return data;
-    }
-
-    /**
-     * Set a filter for the metadata update notification and update
-     * retrieval. The caller provides 2 set of metadata keys, allowed
-     * and blocked. The blocked set always takes precedence over the
-     * allowed one.
-     * Metadata.MATCH_ALL and Metadata.MATCH_NONE are 2 sets available as
-     * shorthands to allow/block all or no metadata.
-     *
-     * By default, there is no filter set.
-     *
-     * @param allow Is the set of metadata the client is interested
-     *              in receiving new notifications for.
-     * @param block Is the set of metadata the client is not interested
-     *              in receiving new notifications for.
-     * @return The call status code.
-     *
-     // FIXME: unhide.
-     * {@hide}
-     */
-    @Override
-    public int setMetadataFilter(Set<Integer> allow, Set<Integer> block) {
-        // Do our serialization manually instead of calling
-        // Parcel.writeArray since the sets are made of the same type
-        // we avoid paying the price of calling writeValue (used by
-        // writeArray) which burns an extra int per element to encode
-        // the type.
-        Parcel request =  newRequest();
-
-        // The parcel starts already with an interface token. There
-        // are 2 filters. Each one starts with a 4bytes number to
-        // store the len followed by a number of int (4 bytes as well)
-        // representing the metadata type.
-        int capacity = request.dataSize() + 4 * (1 + allow.size() + 1 + block.size());
-
-        if (request.dataCapacity() < capacity) {
-            request.setDataCapacity(capacity);
-        }
-
-        request.writeInt(allow.size());
-        for(Integer t: allow) {
-            request.writeInt(t);
-        }
-        request.writeInt(block.size());
-        for(Integer t: block) {
-            request.writeInt(t);
-        }
-        return native_setMetadataFilter(request);
-    }
-
-    /**
      * Resets the MediaPlayer2 to its uninitialized state. After calling
      * this method, you will have to initialize it again by setting the
      * data source and calling prepare().
@@ -1802,32 +1690,6 @@
 
     private native void _setAuxEffectSendLevel(float level);
 
-    /*
-     * @param update_only If true fetch only the set of metadata that have
-     *                    changed since the last invocation of getMetadata.
-     *                    The set is built using the unfiltered
-     *                    notifications the native player sent to the
-     *                    MediaPlayer2Manager during that period of
-     *                    time. If false, all the metadatas are considered.
-     * @param apply_filter  If true, once the metadata set has been built based on
-     *                     the value update_only, the current filter is applied.
-     * @param reply[out] On return contains the serialized
-     *                   metadata. Valid only if the call was successful.
-     * @return The status code.
-     */
-    private native final boolean native_getMetadata(boolean update_only,
-                                                    boolean apply_filter,
-                                                    Parcel reply);
-
-    /*
-     * @param request Parcel with the 2 serialized lists of allowed
-     *                metadata types followed by the one to be
-     *                dropped. Each list starts with an integer
-     *                indicating the number of metadata type elements.
-     * @return The status code.
-     */
-    private native final int native_setMetadataFilter(Parcel request);
-
     private static native final void native_init();
     private native final void native_setup(Object mediaplayer2_this);
     private native final void native_finalize();
@@ -1903,25 +1765,6 @@
             mFormat = format;
         }
 
-        /**
-         * Flatten this object in to a Parcel.
-         *
-         * @param dest The Parcel in which the object should be written.
-         * @param flags Additional flags about how the object should be written.
-         * May be 0 or {@link android.os.Parcelable#PARCELABLE_WRITE_RETURN_VALUE}.
-         */
-        /* package private */ void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(mTrackType);
-            dest.writeString(getLanguage());
-
-            if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
-                dest.writeString(mFormat.getString(MediaFormat.KEY_MIME));
-                dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_AUTOSELECT));
-                dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_DEFAULT));
-                dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE));
-            }
-        }
-
         @Override
         public String toString() {
             StringBuilder out = new StringBuilder(128);
@@ -2731,12 +2574,13 @@
                 }
 
                 if (dsd != null) {
-                    synchronized (mEventCbLock) {
-                        for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
-                            cb.first.execute(() -> cb.second.onInfo(
-                                    mMediaPlayer, dsd, MEDIA_INFO_PREPARED, 0));
+                    sendEvent(new EventNotifier() {
+                        @Override
+                        public void notify(EventCallback callback) {
+                            callback.onInfo(
+                                    mMediaPlayer, dsd, MEDIA_INFO_PREPARED, 0);
                         }
-                    }
+                    });
                 }
 
                 synchronized (mSrcLock) {
@@ -2784,12 +2628,13 @@
 
                     // notifying the client outside the lock
                     if (drmInfo != null) {
-                        synchronized (mEventCbLock) {
-                            for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
-                                cb.first.execute(() -> cb.second.onDrmInfo(
-                                        mMediaPlayer, dsd, drmInfo));
+                        sendDrmEvent(new DrmEventNotifier() {
+                            @Override
+                            public void notify(DrmEventCallback callback) {
+                                callback.onDrmInfo(
+                                        mMediaPlayer, dsd, drmInfo);
                             }
-                        }
+                        });
                     }
                 } else {
                     Log.w(TAG, "MEDIA_DRM_INFO msg.obj of unexpected type " + msg.obj);
@@ -2800,12 +2645,13 @@
             case MEDIA_PLAYBACK_COMPLETE:
             {
                 if (isCurrentSrcId) {
-                    synchronized (mEventCbLock) {
-                        for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
-                            cb.first.execute(() -> cb.second.onInfo(
-                                    mMediaPlayer, dsd, MEDIA_INFO_DATA_SOURCE_END, 0));
+                    sendEvent(new EventNotifier() {
+                        @Override
+                        public void notify(EventCallback callback) {
+                            callback.onInfo(
+                                    mMediaPlayer, dsd, MEDIA_INFO_DATA_SOURCE_END, 0);
                         }
-                    }
+                    });
                     stayAwake(false);
 
                     synchronized (mSrcLock) {
@@ -2843,13 +2689,13 @@
             case MEDIA_BUFFERING_UPDATE:
             {
                 final int percent = msg.arg1;
-                synchronized (mEventCbLock) {
-                    for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
-                        cb.first.execute(() -> cb.second.onInfo(
-                                mMediaPlayer, dsd, MEDIA_INFO_BUFFERING_UPDATE,
-                                percent));
+                sendEvent(new EventNotifier() {
+                    @Override
+                    public void notify(EventCallback callback) {
+                        callback.onInfo(
+                                mMediaPlayer, dsd, MEDIA_INFO_BUFFERING_UPDATE, percent);
                     }
-                }
+                });
 
                 synchronized (mSrcLock) {
                     if (isCurrentSrcId) {
@@ -2888,26 +2734,33 @@
             {
                 final int width = msg.arg1;
                 final int height = msg.arg2;
-                synchronized (mEventCbLock) {
-                    for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
-                        cb.first.execute(() -> cb.second.onVideoSizeChanged(
-                                mMediaPlayer, dsd, width, height));
+                sendEvent(new EventNotifier() {
+                    @Override
+                    public void notify(EventCallback callback) {
+                        callback.onVideoSizeChanged(
+                                mMediaPlayer, dsd, width, height);
                     }
-                }
+                });
                 return;
             }
 
             case MEDIA_ERROR:
             {
                 Log.e(TAG, "Error (" + msg.arg1 + "," + msg.arg2 + ")");
-                synchronized (mEventCbLock) {
-                    for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
-                        cb.first.execute(() -> cb.second.onError(
-                                mMediaPlayer, dsd, what, extra));
-                        cb.first.execute(() -> cb.second.onInfo(
-                                mMediaPlayer, dsd, MEDIA_INFO_DATA_SOURCE_END, 0));
+                sendEvent(new EventNotifier() {
+                    @Override
+                    public void notify(EventCallback callback) {
+                        callback.onError(
+                                mMediaPlayer, dsd, what, extra);
                     }
-                }
+                });
+                sendEvent(new EventNotifier() {
+                    @Override
+                    public void notify(EventCallback callback) {
+                        callback.onInfo(
+                                mMediaPlayer, dsd, MEDIA_INFO_DATA_SOURCE_END, 0);
+                    }
+                });
                 stayAwake(false);
                 return;
             }
@@ -2947,12 +2800,13 @@
                         break;
                 }
 
-                synchronized (mEventCbLock) {
-                    for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
-                        cb.first.execute(() -> cb.second.onInfo(
-                                mMediaPlayer, dsd, what, extra));
+                sendEvent(new EventNotifier() {
+                    @Override
+                    public void notify(EventCallback callback) {
+                        callback.onInfo(
+                                mMediaPlayer, dsd, what, extra);
                     }
-                }
+                });
 
                 if (msg.arg1 == MEDIA_INFO_DATA_SOURCE_START) {
                     if (isCurrentSrcId) {
@@ -2989,12 +2843,13 @@
                     text = null;
                 }
 
-                synchronized (mEventCbLock) {
-                    for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
-                        cb.first.execute(() -> cb.second.onTimedText(
-                                mMediaPlayer, dsd, text));
+                sendEvent(new EventNotifier() {
+                    @Override
+                    public void notify(EventCallback callback) {
+                        callback.onTimedText(
+                                mMediaPlayer, dsd, text);
                     }
-                }
+                });
                 return;
             }
 
@@ -3014,12 +2869,13 @@
                             in.next().getInt64Value(),  // startTimeUs
                             in.next().getInt64Value(),  // durationUs
                             in.next().getBytesValue().toByteArray());  // data
-                    synchronized (mEventCbLock) {
-                        for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
-                            cb.first.execute(() -> cb.second.onSubtitleData(
-                                    mMediaPlayer, dsd, data));
+                    sendEvent(new EventNotifier() {
+                        @Override
+                        public void notify(EventCallback callback) {
+                            callback.onSubtitleData(
+                                    mMediaPlayer, dsd, data);
                         }
-                    }
+                    });
                 }
                 return;
             }
@@ -3043,12 +2899,13 @@
                     data = null;
                 }
 
-                synchronized (mEventCbLock) {
-                    for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
-                        cb.first.execute(() -> cb.second.onTimedMetaDataAvailable(
-                                mMediaPlayer, dsd, data));
+                sendEvent(new EventNotifier() {
+                    @Override
+                    public void notify(EventCallback callback) {
+                        callback.onTimedMetaDataAvailable(
+                                mMediaPlayer, dsd, data);
                     }
-                }
+                });
                 return;
             }
 
@@ -3181,6 +3038,40 @@
         }
     }
 
+    private void sendEvent(final EventNotifier notifier) {
+        synchronized (mEventCbLock) {
+            try {
+                for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
+                    cb.first.execute(() -> notifier.notify(cb.second));
+                }
+            } catch (RejectedExecutionException e) {
+                // The executor has been shut down.
+                Log.w(TAG, "The executor has been shut down. Ignoring event.");
+            }
+        }
+    }
+
+    private void sendDrmEvent(final DrmEventNotifier notifier) {
+        synchronized (mDrmEventCbLock) {
+            try {
+                for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
+                    cb.first.execute(() -> notifier.notify(cb.second));
+                }
+            } catch (RejectedExecutionException e) {
+                // The executor has been shut down.
+                Log.w(TAG, "The executor has been shut down. Ignoring drm event.");
+            }
+        }
+    }
+
+    private interface EventNotifier {
+        void notify(EventCallback callback);
+    }
+
+    private interface DrmEventNotifier {
+        void notify(DrmEventCallback callback);
+    }
+
     // Modular DRM begin
 
     /**
@@ -3431,12 +3322,13 @@
 
         // if finished successfully without provisioning, call the callback outside the lock
         if (allDoneWithoutProvisioning) {
-            synchronized (mDrmEventCbLock) {
-                for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
-                    cb.first.execute(() -> cb.second.onDrmPrepared(
-                            this, mCurrentDSD, PREPARE_DRM_STATUS_SUCCESS));
+            sendDrmEvent(new DrmEventNotifier() {
+                @Override
+                public void notify(DrmEventCallback callback) {
+                    callback.onDrmPrepared(
+                            MediaPlayer2Impl.this, mCurrentDSD, PREPARE_DRM_STATUS_SUCCESS);
                 }
-            }
+            });
         }
 
     }
@@ -4116,12 +4008,13 @@
                 } // synchronized
 
                 // calling the callback outside the lock
-                synchronized (mDrmEventCbLock) {
-                    for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
-                        cb.first.execute(() -> cb.second.onDrmPrepared(
-                                mediaPlayer, mCurrentDSD, status));
+                sendDrmEvent(new DrmEventNotifier() {
+                    @Override
+                    public void notify(DrmEventCallback callback) {
+                        callback.onDrmPrepared(
+                                mediaPlayer, mCurrentDSD, status);
                     }
-                }
+                });
             } else {   // blocking mode already has the lock
 
                 // continuing with prepareDrm
@@ -4780,12 +4673,13 @@
             if (mMediaCallType == CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED) {
                 return;
             }
-            synchronized (mEventCbLock) {
-                for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
-                    cb.first.execute(() -> cb.second.onCallCompleted(
-                            MediaPlayer2Impl.this, mDSD, mMediaCallType, status));
+            sendEvent(new EventNotifier() {
+                @Override
+                public void notify(EventCallback callback) {
+                    callback.onCallCompleted(
+                            MediaPlayer2Impl.this, mDSD, mMediaCallType, status);
                 }
-            }
+            });
         }
     };
 
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 43bee85..ffeff4d 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -34,6 +34,7 @@
 import android.hardware.display.WifiDisplay;
 import android.hardware.display.WifiDisplayStatus;
 import android.media.session.MediaSession;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Process;
@@ -2064,7 +2065,7 @@
         }
 
         /** @hide */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public boolean isDefault() {
             return this == sStatic.mDefaultAudioVideo;
         }
diff --git a/media/java/android/media/MiniThumbFile.java b/media/java/android/media/MiniThumbFile.java
index 716e0cb..f704acd 100644
--- a/media/java/android/media/MiniThumbFile.java
+++ b/media/java/android/media/MiniThumbFile.java
@@ -18,9 +18,12 @@
 
 import android.annotation.UnsupportedAppUsage;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Environment;
 import android.util.Log;
 
+import dalvik.system.VMRuntime;
+
 import java.io.File;
 import java.io.IOException;
 import java.io.RandomAccessFile;
@@ -42,7 +45,10 @@
  *
  * @hide This file is shared between MediaStore and MediaProvider and should remained internal use
  *       only.
+ * @deprecated thumbnails are now maintained in separate files, and this file
+ *             format is no longer used.
  */
+@Deprecated
 public class MiniThumbFile {
     private static final String TAG = "MiniThumbFile";
     private static final int MINI_THUMB_DATA_FILE_VERSION = 4;
@@ -69,6 +75,9 @@
     }
 
     public static synchronized MiniThumbFile instance(Uri uri) {
+        if (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.Q) {
+            throw new UnsupportedOperationException();
+        }
         String type = uri.getPathSegments().get(1);
         MiniThumbFile file = sThumbFiles.get(type);
         // Log.v(TAG, "get minithumbfile for type: "+type);
diff --git a/media/java/android/media/PlaybackParams.java b/media/java/android/media/PlaybackParams.java
index 6594dd7..3fe1a32 100644
--- a/media/java/android/media/PlaybackParams.java
+++ b/media/java/android/media/PlaybackParams.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -94,7 +95,7 @@
     private static final int SET_AUDIO_FALLBACK_MODE = 1 << 2;
     @UnsupportedAppUsage
     private static final int SET_AUDIO_STRETCH_MODE  = 1 << 3;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private int mSet = 0;
 
     // params
@@ -104,7 +105,7 @@
     private int mAudioStretchMode = AUDIO_STRETCH_MODE_DEFAULT;
     @UnsupportedAppUsage
     private float mPitch = 1.0f;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private float mSpeed = 1.0f;
 
     public PlaybackParams() {
diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java
index 1a456f6..9746842 100644
--- a/media/java/android/media/audiofx/AudioEffect.java
+++ b/media/java/android/media/audiofx/AudioEffect.java
@@ -21,6 +21,7 @@
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityThread;
+import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -872,7 +873,7 @@
      * In case of failure, the returned value is negative and implementation specific.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public int command(int cmdCode, byte[] command, byte[] reply)
             throws IllegalStateException {
         checkState("command()");
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 7681cc3..3870124 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -88,8 +88,6 @@
     name: "libmedia2_jni",
 
     srcs: [
-        "android_media_Media2HTTPConnection.cpp",
-        "android_media_Media2HTTPService.cpp",
         "android_media_Media2DataSource.cpp",
         "android_media_MediaMetricsJNI.cpp",
         "android_media_MediaPlayer2.cpp",
@@ -142,6 +140,7 @@
         "libstagefright_player2",
         "libstagefright_rtsp",
         "libstagefright_timedtext2",
+        "libmedia2_jni_core",
     ],
 
     group_static_libs: true,
diff --git a/media/jni/android_media_Media2HTTPConnection.cpp b/media/jni/android_media_Media2HTTPConnection.cpp
deleted file mode 100644
index d02ee06..0000000
--- a/media/jni/android_media_Media2HTTPConnection.cpp
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "Media2HTTPConnection-JNI"
-#include <utils/Log.h>
-
-#include <mediaplayer2/JavaVMHelper.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <nativehelper/ScopedLocalRef.h>
-
-#include "android_media_Media2HTTPConnection.h"
-#include "android_util_Binder.h"
-
-#include "log/log.h"
-#include "jni.h"
-#include <nativehelper/JNIHelp.h>
-
-namespace android {
-
-static const size_t kBufferSize = 32768;
-
-JMedia2HTTPConnection::JMedia2HTTPConnection(JNIEnv *env, jobject thiz) {
-    mMedia2HTTPConnectionObj = env->NewGlobalRef(thiz);
-    CHECK(mMedia2HTTPConnectionObj != NULL);
-
-    ScopedLocalRef<jclass> media2HTTPConnectionClass(
-            env, env->GetObjectClass(mMedia2HTTPConnectionObj));
-    CHECK(media2HTTPConnectionClass.get() != NULL);
-
-    mConnectMethod = env->GetMethodID(
-            media2HTTPConnectionClass.get(),
-            "connect",
-            "(Ljava/lang/String;Ljava/lang/String;)Z");
-    CHECK(mConnectMethod != NULL);
-
-    mDisconnectMethod = env->GetMethodID(
-            media2HTTPConnectionClass.get(),
-            "disconnect",
-            "()V");
-    CHECK(mDisconnectMethod != NULL);
-
-    mReadAtMethod = env->GetMethodID(
-            media2HTTPConnectionClass.get(),
-            "readAt",
-            "(J[BI)I");
-    CHECK(mReadAtMethod != NULL);
-
-    mGetSizeMethod = env->GetMethodID(
-            media2HTTPConnectionClass.get(),
-            "getSize",
-            "()J");
-    CHECK(mGetSizeMethod != NULL);
-
-    mGetMIMETypeMethod = env->GetMethodID(
-            media2HTTPConnectionClass.get(),
-            "getMIMEType",
-            "()Ljava/lang/String;");
-    CHECK(mGetMIMETypeMethod != NULL);
-
-    mGetUriMethod = env->GetMethodID(
-            media2HTTPConnectionClass.get(),
-            "getUri",
-            "()Ljava/lang/String;");
-    CHECK(mGetUriMethod != NULL);
-
-    ScopedLocalRef<jbyteArray> tmp(
-        env, env->NewByteArray(kBufferSize));
-    mByteArrayObj = (jbyteArray)env->NewGlobalRef(tmp.get());
-    CHECK(mByteArrayObj != NULL);
-}
-
-JMedia2HTTPConnection::~JMedia2HTTPConnection() {
-    JNIEnv *env = JavaVMHelper::getJNIEnv();
-    env->DeleteGlobalRef(mMedia2HTTPConnectionObj);
-    env->DeleteGlobalRef(mByteArrayObj);
-}
-
-bool JMedia2HTTPConnection::connect(
-        const char *uri, const KeyedVector<String8, String8> *headers) {
-    String8 tmp("");
-    if (headers != NULL) {
-        for (size_t i = 0; i < headers->size(); ++i) {
-            tmp.append(headers->keyAt(i));
-            tmp.append(String8(": "));
-            tmp.append(headers->valueAt(i));
-            tmp.append(String8("\r\n"));
-        }
-    }
-
-    JNIEnv* env = JavaVMHelper::getJNIEnv();
-    jstring juri = env->NewStringUTF(uri);
-    jstring jheaders = env->NewStringUTF(tmp.string());
-
-    jboolean ret =
-        env->CallBooleanMethod(mMedia2HTTPConnectionObj, mConnectMethod, juri, jheaders);
-
-    env->DeleteLocalRef(juri);
-    env->DeleteLocalRef(jheaders);
-
-    return (bool)ret;
-}
-
-void JMedia2HTTPConnection::disconnect() {
-    JNIEnv* env = JavaVMHelper::getJNIEnv();
-    env->CallVoidMethod(mMedia2HTTPConnectionObj, mDisconnectMethod);
-}
-
-ssize_t JMedia2HTTPConnection::readAt(off64_t offset, void *data, size_t size) {
-    JNIEnv* env = JavaVMHelper::getJNIEnv();
-
-    if (size > kBufferSize) {
-        size = kBufferSize;
-    }
-
-    jint n = env->CallIntMethod(
-            mMedia2HTTPConnectionObj, mReadAtMethod, (jlong)offset, mByteArrayObj, (jint)size);
-
-    if (n > 0) {
-        env->GetByteArrayRegion(
-                mByteArrayObj,
-                0,
-                n,
-                (jbyte *)data);
-    }
-
-    return n;
-}
-
-off64_t JMedia2HTTPConnection::getSize() {
-    JNIEnv* env = JavaVMHelper::getJNIEnv();
-    return (off64_t)(env->CallLongMethod(mMedia2HTTPConnectionObj, mGetSizeMethod));
-}
-
-status_t JMedia2HTTPConnection::getMIMEType(String8 *mimeType) {
-    JNIEnv* env = JavaVMHelper::getJNIEnv();
-    jstring jmime = (jstring)env->CallObjectMethod(mMedia2HTTPConnectionObj, mGetMIMETypeMethod);
-    jboolean flag = env->ExceptionCheck();
-    if (flag) {
-        env->ExceptionClear();
-        return UNKNOWN_ERROR;
-    }
-
-    const char *str = env->GetStringUTFChars(jmime, 0);
-    if (str != NULL) {
-        *mimeType = String8(str);
-    } else {
-        *mimeType = "application/octet-stream";
-    }
-    env->ReleaseStringUTFChars(jmime, str);
-    return OK;
-}
-
-status_t JMedia2HTTPConnection::getUri(String8 *uri) {
-    JNIEnv* env = JavaVMHelper::getJNIEnv();
-    jstring juri = (jstring)env->CallObjectMethod(mMedia2HTTPConnectionObj, mGetUriMethod);
-    jboolean flag = env->ExceptionCheck();
-    if (flag) {
-        env->ExceptionClear();
-        return UNKNOWN_ERROR;
-    }
-
-    const char *str = env->GetStringUTFChars(juri, 0);
-    *uri = String8(str);
-    env->ReleaseStringUTFChars(juri, str);
-    return OK;
-}
-
-}  // namespace android
diff --git a/media/jni/android_media_Media2HTTPConnection.h b/media/jni/android_media_Media2HTTPConnection.h
deleted file mode 100644
index 14bc677..0000000
--- a/media/jni/android_media_Media2HTTPConnection.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _ANDROID_MEDIA_MEDIA2HTTPCONNECTION_H_
-#define _ANDROID_MEDIA_MEDIA2HTTPCONNECTION_H_
-
-#include "jni.h"
-
-#include <media/MediaHTTPConnection.h>
-#include <media/stagefright/foundation/ABase.h>
-
-namespace android {
-
-struct JMedia2HTTPConnection : public MediaHTTPConnection {
-    JMedia2HTTPConnection(JNIEnv *env, jobject thiz);
-
-    virtual bool connect(
-            const char *uri, const KeyedVector<String8, String8> *headers) override;
-
-    virtual void disconnect() override;
-    virtual ssize_t readAt(off64_t offset, void *data, size_t size) override;
-    virtual off64_t getSize() override;
-    virtual status_t getMIMEType(String8 *mimeType) override;
-    virtual status_t getUri(String8 *uri) override;
-
-protected:
-    virtual ~JMedia2HTTPConnection();
-
-private:
-    jobject mMedia2HTTPConnectionObj;
-    jmethodID mConnectMethod;
-    jmethodID mDisconnectMethod;
-    jmethodID mReadAtMethod;
-    jmethodID mGetSizeMethod;
-    jmethodID mGetMIMETypeMethod;
-    jmethodID mGetUriMethod;
-
-    jbyteArray mByteArrayObj;
-
-    DISALLOW_EVIL_CONSTRUCTORS(JMedia2HTTPConnection);
-};
-
-}  // namespace android
-
-#endif  // _ANDROID_MEDIA_MEDIA2HTTPCONNECTION_H_
diff --git a/media/jni/android_media_Media2HTTPService.cpp b/media/jni/android_media_Media2HTTPService.cpp
deleted file mode 100644
index 1c63889..0000000
--- a/media/jni/android_media_Media2HTTPService.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "Media2HTTPService-JNI"
-#include <utils/Log.h>
-
-#include "android_media_Media2HTTPConnection.h"
-#include "android_media_Media2HTTPService.h"
-
-#include "log/log.h"
-#include "jni.h"
-#include <nativehelper/JNIHelp.h>
-
-#include <mediaplayer2/JavaVMHelper.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <nativehelper/ScopedLocalRef.h>
-
-namespace android {
-
-JMedia2HTTPService::JMedia2HTTPService(JNIEnv *env, jobject thiz) {
-    mMedia2HTTPServiceObj = env->NewGlobalRef(thiz);
-    CHECK(mMedia2HTTPServiceObj != NULL);
-
-    ScopedLocalRef<jclass> media2HTTPServiceClass(env, env->GetObjectClass(mMedia2HTTPServiceObj));
-    CHECK(media2HTTPServiceClass.get() != NULL);
-
-    mMakeHTTPConnectionMethod = env->GetMethodID(
-            media2HTTPServiceClass.get(),
-            "makeHTTPConnection",
-            "()Landroid/media/Media2HTTPConnection;");
-    CHECK(mMakeHTTPConnectionMethod != NULL);
-}
-
-JMedia2HTTPService::~JMedia2HTTPService() {
-    JNIEnv *env = JavaVMHelper::getJNIEnv();
-    env->DeleteGlobalRef(mMedia2HTTPServiceObj);
-}
-
-sp<MediaHTTPConnection> JMedia2HTTPService::makeHTTPConnection() {
-    JNIEnv* env = JavaVMHelper::getJNIEnv();
-    jobject media2HTTPConnectionObj =
-        env->CallObjectMethod(mMedia2HTTPServiceObj, mMakeHTTPConnectionMethod);
-
-    return new JMedia2HTTPConnection(env, media2HTTPConnectionObj);
-}
-
-}  // namespace android
diff --git a/media/jni/android_media_Media2HTTPService.h b/media/jni/android_media_Media2HTTPService.h
deleted file mode 100644
index 30d03f5..0000000
--- a/media/jni/android_media_Media2HTTPService.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _ANDROID_MEDIA_MEDIA2HTTPSERVICE_H_
-#define _ANDROID_MEDIA_MEDIA2HTTPSERVICE_H_
-
-#include "jni.h"
-
-#include <media/MediaHTTPService.h>
-#include <media/stagefright/foundation/ABase.h>
-
-namespace android {
-
-struct JMedia2HTTPService : public MediaHTTPService {
-    JMedia2HTTPService(JNIEnv *env, jobject thiz);
-
-    virtual sp<MediaHTTPConnection> makeHTTPConnection() override;
-
-protected:
-    virtual ~JMedia2HTTPService();
-
-private:
-    jobject mMedia2HTTPServiceObj;
-
-    jmethodID mMakeHTTPConnectionMethod;
-
-    DISALLOW_EVIL_CONSTRUCTORS(JMedia2HTTPService);
-};
-
-}  // namespace android
-
-#endif  // _ANDROID_MEDIA_MEDIA2HTTPSERVICE_H_
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 3490ff8..5037209 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -108,8 +108,9 @@
 } gCodecInfo;
 
 struct fields_t {
-    jfieldID context;
     jmethodID postEventFromNativeID;
+    jmethodID lockAndGetContextID;
+    jmethodID setAndUnlockContextID;
     jfieldID cryptoInfoNumSubSamplesID;
     jfieldID cryptoInfoNumBytesOfClearDataID;
     jfieldID cryptoInfoNumBytesOfEncryptedDataID;
@@ -931,7 +932,7 @@
 
 static sp<JMediaCodec> setMediaCodec(
         JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec) {
-    sp<JMediaCodec> old = (JMediaCodec *)env->GetLongField(thiz, gFields.context);
+    sp<JMediaCodec> old = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
     if (codec != NULL) {
         codec->incStrong(thiz);
     }
@@ -944,13 +945,15 @@
         old->release();
         old->decStrong(thiz);
     }
-    env->SetLongField(thiz, gFields.context, (jlong)codec.get());
+    env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
 
     return old;
 }
 
 static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
-    return (JMediaCodec *)env->GetLongField(thiz, gFields.context);
+    sp<JMediaCodec> codec = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
+    env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
+    return codec;
 }
 
 static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
@@ -1876,15 +1879,21 @@
             env, env->FindClass("android/media/MediaCodec"));
     CHECK(clazz.get() != NULL);
 
-    gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
-    CHECK(gFields.context != NULL);
-
     gFields.postEventFromNativeID =
         env->GetMethodID(
                 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V");
-
     CHECK(gFields.postEventFromNativeID != NULL);
 
+    gFields.lockAndGetContextID =
+        env->GetMethodID(
+                clazz.get(), "lockAndGetContext", "()J");
+    CHECK(gFields.lockAndGetContextID != NULL);
+
+    gFields.setAndUnlockContextID =
+        env->GetMethodID(
+                clazz.get(), "setAndUnlockContext", "(J)V");
+    CHECK(gFields.setAndUnlockContextID != NULL);
+
     jfieldID field;
     field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_UNENCRYPTED", "I");
     CHECK(field != NULL);
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index d4c84b5..1a844cc 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -30,6 +30,7 @@
 #include <media/stagefright/foundation/ByteUtils.h>  // for FOURCC definition
 #include <mediaplayer2/JAudioTrack.h>
 #include <mediaplayer2/JavaVMHelper.h>
+#include <mediaplayer2/JMedia2HTTPService.h>
 #include <mediaplayer2/mediaplayer2.h>
 #include <stdio.h>
 #include <assert.h>
@@ -45,7 +46,6 @@
 #include "utils/KeyedVector.h"
 #include "utils/String8.h"
 #include "android_media_BufferingParams.h"
-#include "android_media_Media2HTTPService.h"
 #include "android_media_Media2DataSource.h"
 #include "android_media_MediaMetricsJNI.h"
 #include "android_media_PlaybackParams.h"
diff --git a/media/lib/remotedisplay/OWNERS b/media/lib/remotedisplay/OWNERS
new file mode 100644
index 0000000..7e7335d
--- /dev/null
+++ b/media/lib/remotedisplay/OWNERS
@@ -0,0 +1 @@
+michaelwr@google.com
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 43847cc..24d003b 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -49,6 +49,7 @@
         "sharedmem.cpp",
         "storage_manager.cpp",
         "surface_texture.cpp",
+        "system_fonts.cpp",
         "trace.cpp",
     ],
 
@@ -65,6 +66,7 @@
         "libandroid_runtime",
         "libnetd_client",
         "libhwui",
+        "libxml2",
     ],
 
     static_libs: [
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index ac5ded6..9f48bc9 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -212,6 +212,18 @@
     ASurfaceTexture_getTransformMatrix; # introduced=28
     ASurfaceTexture_release; # introduced=28
     ASurfaceTexture_updateTexImage; # introduced=28
+    ASystemFontIterator_open; # introduced=29
+    ASystemFontIterator_close; # introduced=29
+    ASystemFontIterator_next; # introduced=29
+    ASystemFont_close; # introduced=29
+    ASystemFont_getFontFilePath; # introduced=29
+    ASystemFont_getWeight; # introduced=29
+    ASystemFont_isItalic; # introduced=29
+    ASystemFont_getLocale; # introduced=29
+    ASystemFont_getCollectionIndex; # introduced=29
+    ASystemFont_getAxisCount; # introduced=29
+    ASystemFont_getAxisTag; # introduced=29
+    ASystemFont_getAxisValue; # introduced=29
     ATrace_beginSection; # introduced=23
     ATrace_endSection; # introduced=23
     ATrace_isEnabled; # introduced=23
diff --git a/native/android/system_fonts.cpp b/native/android/system_fonts.cpp
new file mode 100644
index 0000000..b95adad
--- /dev/null
+++ b/native/android/system_fonts.cpp
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <jni.h>
+
+#include <android/system_fonts.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <libxml/tree.h>
+#include <log/log.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+struct XmlCharDeleter {
+    void operator()(xmlChar* b) { xmlFree(b); }
+};
+
+struct XmlDocDeleter {
+    void operator()(xmlDoc* d) { xmlFreeDoc(d); }
+};
+
+using XmlCharUniquePtr = std::unique_ptr<xmlChar, XmlCharDeleter>;
+using XmlDocUniquePtr = std::unique_ptr<xmlDoc, XmlDocDeleter>;
+
+struct ASystemFontIterator {
+    XmlDocUniquePtr mXmlDoc;
+    xmlNode* mFontNode;
+};
+
+struct ASystemFont {
+    std::string mFilePath;
+    std::unique_ptr<std::string> mLocale;
+    uint16_t mWeight;
+    bool mItalic;
+    uint32_t mCollectionIndex;
+    std::vector<std::pair<uint32_t, float>> mAxes;
+};
+
+namespace {
+
+std::string xmlTrim(const std::string& in) {
+    if (in.empty()) {
+        return in;
+    }
+    const char XML_SPACES[] = "\u0020\u000D\u000A\u0009";
+    const size_t start = in.find_first_not_of(XML_SPACES);  // inclusive
+    if (start == std::string::npos) {
+        return "";
+    }
+    const size_t end = in.find_last_not_of(XML_SPACES);     // inclusive
+    if (end == std::string::npos) {
+        return "";
+    }
+    return in.substr(start, end - start + 1 /* +1 since end is inclusive */);
+}
+
+const xmlChar* FAMILY_TAG = BAD_CAST("family");
+const xmlChar* FONT_TAG = BAD_CAST("font");
+
+xmlNode* firstElement(xmlNode* node, const xmlChar* tag) {
+    for (xmlNode* child = node->children; child; child = child->next) {
+        if (xmlStrEqual(child->name, tag)) {
+            return child;
+        }
+    }
+    return nullptr;
+}
+
+xmlNode* nextSibling(xmlNode* node, const xmlChar* tag) {
+    while ((node = node->next) != nullptr) {
+        if (xmlStrEqual(node->name, tag)) {
+            return node;
+        }
+    }
+    return nullptr;
+}
+
+void copyFont(ASystemFontIterator* ite, ASystemFont* out) {
+    const xmlChar* LOCALE_ATTR_NAME = BAD_CAST("lang");
+    XmlCharUniquePtr filePathStr(
+            xmlNodeListGetString(ite->mXmlDoc.get(), ite->mFontNode->xmlChildrenNode, 1));
+    out->mFilePath = "/system/fonts/" + xmlTrim(
+            std::string(filePathStr.get(), filePathStr.get() + xmlStrlen(filePathStr.get())));
+
+    const xmlChar* WEIGHT_ATTR_NAME = BAD_CAST("weight");
+    XmlCharUniquePtr weightStr(xmlGetProp(ite->mFontNode, WEIGHT_ATTR_NAME));
+    out->mWeight = weightStr ?
+            strtol(reinterpret_cast<const char*>(weightStr.get()), nullptr, 10) : 400;
+
+    const xmlChar* STYLE_ATTR_NAME = BAD_CAST("style");
+    const xmlChar* ITALIC_ATTR_VALUE = BAD_CAST("italic");
+    XmlCharUniquePtr styleStr(xmlGetProp(ite->mFontNode, STYLE_ATTR_NAME));
+    out->mItalic = styleStr ? xmlStrEqual(styleStr.get(), ITALIC_ATTR_VALUE) : false;
+
+    const xmlChar* INDEX_ATTR_NAME = BAD_CAST("index");
+    XmlCharUniquePtr indexStr(xmlGetProp(ite->mFontNode, INDEX_ATTR_NAME));
+    out->mCollectionIndex =  indexStr ?
+            strtol(reinterpret_cast<const char*>(indexStr.get()), nullptr, 10) : 0;
+
+    XmlCharUniquePtr localeStr(xmlGetProp(ite->mXmlDoc->parent, LOCALE_ATTR_NAME));
+    out->mLocale.reset(
+            localeStr ? new std::string(reinterpret_cast<const char*>(localeStr.get())) : nullptr);
+
+    const xmlChar* TAG_ATTR_NAME = BAD_CAST("tag");
+    const xmlChar* STYLEVALUE_ATTR_NAME = BAD_CAST("stylevalue");
+    const xmlChar* AXIS_TAG = BAD_CAST("axis");
+    out->mAxes.clear();
+    for (xmlNode* axis = firstElement(ite->mFontNode, AXIS_TAG); axis;
+            axis = nextSibling(axis, AXIS_TAG)) {
+        XmlCharUniquePtr tagStr(xmlGetProp(axis, TAG_ATTR_NAME));
+        if (!tagStr || xmlStrlen(tagStr.get()) != 4) {
+            continue;  // Tag value must be 4 char string
+        }
+
+        XmlCharUniquePtr styleValueStr(xmlGetProp(axis, STYLEVALUE_ATTR_NAME));
+        if (!styleValueStr) {
+            continue;
+        }
+
+        uint32_t tag =
+            static_cast<uint32_t>(tagStr.get()[0] << 24) |
+            static_cast<uint32_t>(tagStr.get()[1] << 16) |
+            static_cast<uint32_t>(tagStr.get()[2] << 8) |
+            static_cast<uint32_t>(tagStr.get()[3]);
+        float styleValue = strtod(reinterpret_cast<const char*>(styleValueStr.get()), nullptr);
+        out->mAxes.push_back(std::make_pair(tag, styleValue));
+    }
+}
+
+bool isFontFileAvailable(const std::string& filePath) {
+    std::string fullPath = filePath;
+    struct stat st = {};
+    if (stat(fullPath.c_str(), &st) != 0) {
+        return false;
+    }
+    return S_ISREG(st.st_mode);
+}
+
+xmlNode* findFirstFontNode(xmlDoc* doc) {
+    xmlNode* familySet = xmlDocGetRootElement(doc);
+    if (familySet == nullptr) {
+        return nullptr;
+    }
+    xmlNode* family = firstElement(familySet, FAMILY_TAG);
+    if (family == nullptr) {
+        return nullptr;
+    }
+
+    xmlNode* font = firstElement(family, FONT_TAG);
+    while (font == nullptr) {
+        family = nextSibling(family, FAMILY_TAG);
+        if (family == nullptr) {
+            return nullptr;
+        }
+        font = firstElement(family, FONT_TAG);
+    }
+    return font;
+}
+
+}  // namespace
+
+ASystemFontIterator* ASystemFontIterator_open() {
+    std::unique_ptr<ASystemFontIterator> ite(new ASystemFontIterator());
+    ite->mXmlDoc.reset(xmlReadFile("/system/etc/fonts.xml", nullptr, 0));
+    return ite.release();
+}
+
+void ASystemFontIterator_close(ASystemFontIterator* ite) {
+    delete ite;
+}
+
+ASystemFont* ASystemFontIterator_next(ASystemFontIterator* ite) {
+    LOG_ALWAYS_FATAL_IF(ite == nullptr, "nullptr has passed as iterator argument");
+    if (ite->mFontNode == nullptr) {
+        if (ite->mXmlDoc == nullptr) {
+            return nullptr;  // Already at the end.
+        } else {
+            // First time to query font.
+            ite->mFontNode = findFirstFontNode(ite->mXmlDoc.get());
+            if (ite->mFontNode == nullptr) {
+                ite->mXmlDoc.reset();
+                return nullptr;  // No font node found.
+            }
+            std::unique_ptr<ASystemFont> font = std::make_unique<ASystemFont>();
+            copyFont(ite, font.get());
+            return font.release();
+        }
+    } else {
+        xmlNode* nextNode = nextSibling(ite->mFontNode, FONT_TAG);
+        while (nextNode == nullptr) {
+            xmlNode* family = nextSibling(ite->mFontNode->parent, FAMILY_TAG);
+            if (family == nullptr) {
+                break;
+            }
+            nextNode = firstElement(family, FONT_TAG);
+        }
+        ite->mFontNode = nextNode;
+        if (nextNode == nullptr) {
+            ite->mXmlDoc.reset();
+            return nullptr;
+        }
+
+        std::unique_ptr<ASystemFont> font = std::make_unique<ASystemFont>();
+        copyFont(ite, font.get());
+        if (!isFontFileAvailable(font->mFilePath)) {
+            // fonts.xml intentionally contains missing font configuration. Skip it.
+            return ASystemFontIterator_next(ite);
+        }
+        return font.release();
+    }
+}
+
+void ASystemFont_close(ASystemFont* font) {
+    delete font;
+}
+
+const char* ASystemFont_getFontFilePath(const ASystemFont* font) {
+    LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed as font argument");
+    return font->mFilePath.c_str();
+}
+
+uint16_t ASystemFont_getWeight(const ASystemFont* font) {
+    LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed as font argument");
+    return font->mWeight;
+}
+
+bool ASystemFont_isItalic(const ASystemFont* font) {
+    LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed as font argument");
+    return font->mItalic;
+}
+
+const char* ASystemFont_getLocale(const ASystemFont* font) {
+    LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed to font argument");
+    return font->mLocale ? nullptr : font->mLocale->c_str();
+}
+
+size_t ASystemFont_getCollectionIndex(const ASystemFont* font) {
+    LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed to font argument");
+    return font->mCollectionIndex;
+}
+
+size_t ASystemFont_getAxisCount(const ASystemFont* font) {
+    LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed to font argument");
+    return font->mAxes.size();
+}
+
+uint32_t ASystemFont_getAxisTag(const ASystemFont* font, uint32_t axisIndex) {
+    LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed to font argument");
+    LOG_ALWAYS_FATAL_IF(axisIndex >= font->mAxes.size(),
+                        "given axis index is out of bounds. (< %zd", font->mAxes.size());
+    return font->mAxes[axisIndex].first;
+}
+
+float ASystemFont_getAxisValue(const ASystemFont* font, uint32_t axisIndex) {
+    LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed to font argument");
+    LOG_ALWAYS_FATAL_IF(axisIndex >= font->mAxes.size(),
+                        "given axis index is out of bounds. (< %zd", font->mAxes.size());
+    return font->mAxes[axisIndex].second;
+}
diff --git a/native/webview/loader/loader.cpp b/native/webview/loader/loader.cpp
index fee2a25..7f71f63 100644
--- a/native/webview/loader/loader.cpp
+++ b/native/webview/loader/loader.cpp
@@ -26,6 +26,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <sys/mman.h>
+#include <sys/prctl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
@@ -58,6 +59,7 @@
           vsize, strerror(errno));
     return JNI_FALSE;
   }
+  prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, addr, vsize, "libwebview reservation");
   gReservedAddress = addr;
   gReservedSize = vsize;
   ALOGV("Reserved %zd bytes at %p", vsize, addr);
diff --git a/packages/CaptivePortalLogin/res/values-de/strings.xml b/packages/CaptivePortalLogin/res/values-de/strings.xml
index e64fb76..d8f7be9 100644
--- a/packages/CaptivePortalLogin/res/values-de/strings.xml
+++ b/packages/CaptivePortalLogin/res/values-de/strings.xml
@@ -7,6 +7,6 @@
     <string name="action_bar_label" msgid="917235635415966620">"Im Netzwerk anmelden"</string>
     <string name="action_bar_title" msgid="5645564790486983117">"In %1$s anmelden"</string>
     <string name="ssl_error_warning" msgid="6653188881418638872">"Im Netzwerk, zu dem du eine Verbindung herstellen möchtest, liegen Sicherheitsprobleme vor."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Beispiel: Die Log-in-Seite gehört möglicherweise nicht zur angezeigten Organisation."</string>
+    <string name="ssl_error_example" msgid="647898534624078900">"Beispiel: Die Log-in-Seite gehört eventuell nicht zur angezeigten Organisation."</string>
     <string name="ssl_error_continue" msgid="6492718244923937110">"Trotzdem in einem Browser fortfahren"</string>
 </resources>
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index 149de13..0ba37ae 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -130,6 +130,22 @@
             mProbeSpec = null;
         }
 
+        mNetworkCallback = new NetworkCallback() {
+            @Override
+            public void onLost(Network lostNetwork) {
+                // If the network disappears while the app is up, exit.
+                if (mNetwork.equals(lostNetwork)) done(Result.UNWANTED);
+            }
+        };
+        mCm.registerNetworkCallback(new NetworkRequest.Builder().build(), mNetworkCallback);
+
+        // If the network has disappeared, exit.
+        final NetworkCapabilities networkCapabilities = mCm.getNetworkCapabilities(mNetwork);
+        if (networkCapabilities == null) {
+            finishAndRemoveTask();
+            return;
+        }
+
         // Also initializes proxy system properties.
         mNetwork = mNetwork.getPrivateDnsBypassingCopy();
         mCm.bindProcessToNetwork(mNetwork);
@@ -139,24 +155,6 @@
         // setContentView initializes the WebView logic which in turn reads the system properties.
         setContentView(R.layout.activity_captive_portal_login);
 
-        // Exit app if Network disappears.
-        final NetworkCapabilities networkCapabilities = mCm.getNetworkCapabilities(mNetwork);
-        if (networkCapabilities == null) {
-            finishAndRemoveTask();
-            return;
-        }
-        mNetworkCallback = new NetworkCallback() {
-            @Override
-            public void onLost(Network lostNetwork) {
-                if (mNetwork.equals(lostNetwork)) done(Result.UNWANTED);
-            }
-        };
-        final NetworkRequest.Builder builder = new NetworkRequest.Builder();
-        for (int transportType : networkCapabilities.getTransportTypes()) {
-            builder.addTransportType(transportType);
-        }
-        mCm.registerNetworkCallback(builder.build(), mNetworkCallback);
-
         getActionBar().setDisplayShowHomeEnabled(false);
         getActionBar().setElevation(0); // remove shadow
         getActionBar().setTitle(getHeaderTitle());
diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp
index 86f9032..1b1bf8d 100644
--- a/packages/CarSystemUI/Android.bp
+++ b/packages/CarSystemUI/Android.bp
@@ -30,6 +30,7 @@
         "SystemUIPluginLib",
         "SystemUISharedLib",
         "SettingsLib",
+        "android.car.user",
         "androidx.car_car",
         "androidx.legacy_legacy-support-v4",
         "androidx.recyclerview_recyclerview",
@@ -51,7 +52,6 @@
     libs: [
         "telephony-common",
         "android.car",
-        "android.car.user",
     ],
 
     manifest: "AndroidManifest.xml",
diff --git a/packages/CarrierDefaultApp/res/values-de/strings.xml b/packages/CarrierDefaultApp/res/values-de/strings.xml
index 927b8f0..95639ad 100644
--- a/packages/CarrierDefaultApp/res/values-de/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-de/strings.xml
@@ -12,6 +12,6 @@
     <string name="mobile_data_status_notification_channel_name" msgid="833999690121305708">"Status der mobilen Datennutzung"</string>
     <string name="action_bar_label" msgid="4290345990334377177">"Bei Mobilfunknetz anmelden"</string>
     <string name="ssl_error_warning" msgid="3127935140338254180">"Im Netzwerk, zu dem du eine Verbindung herstellen möchtest, liegen Sicherheitsprobleme vor."</string>
-    <string name="ssl_error_example" msgid="6188711843183058764">"Beispiel: Die Log-in-Seite gehört möglicherweise nicht zur angezeigten Organisation."</string>
+    <string name="ssl_error_example" msgid="6188711843183058764">"Beispiel: Die Log-in-Seite gehört eventuell nicht zur angezeigten Organisation."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Trotzdem in einem Browser fortfahren"</string>
 </resources>
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
index deb6163..9f38d48 100755
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
@@ -137,6 +137,7 @@
                         UID_UNKNOWN);
                 params.installerPackageName =
                         getIntent().getStringExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME);
+                params.installReason = PackageManager.INSTALL_REASON_USER;
 
                 File file = new File(mPackageURI.getPath());
                 try {
diff --git a/packages/PrintSpooler/res/layout/print_activity.xml b/packages/PrintSpooler/res/layout/print_activity.xml
index 212f398..0ccf13e 100644
--- a/packages/PrintSpooler/res/layout/print_activity.xml
+++ b/packages/PrintSpooler/res/layout/print_activity.xml
@@ -107,6 +107,7 @@
         android:layout_height="wrap_content"
         android:layout_marginStart="16dip"
         android:elevation="@dimen/preview_controls_elevation"
+        android:tint="?android:attr/textColorPrimaryInverse"
         android:background="@drawable/print_button">
     </ImageButton>
 
diff --git a/packages/PrintSpooler/res/values-de/strings.xml b/packages/PrintSpooler/res/values-de/strings.xml
index c02e3c7..e46ff15 100644
--- a/packages/PrintSpooler/res/values-de/strings.xml
+++ b/packages/PrintSpooler/res/values-de/strings.xml
@@ -103,7 +103,7 @@
     <item msgid="3199660090246166812">"Querformat"</item>
   </string-array>
     <string name="print_write_error_message" msgid="5787642615179572543">"Fehler beim Schreiben in Datei"</string>
-    <string name="print_error_default_message" msgid="8602678405502922346">"Fehler. Bitte versuche es erneut."</string>
+    <string name="print_error_default_message" msgid="8602678405502922346">"Fehler. Bitte versuche es noch einmal."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Erneut versuchen"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Dieser Drucker ist momentan nicht verfügbar."</string>
     <string name="print_cannot_load_page" msgid="6179560924492912009">"Vorschau kann nicht angezeigt werden"</string>
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index 943dd84..ee4c954 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -14,6 +14,7 @@
     static_libs: [
         "SettingsLibHelpUtils",
         "SettingsLibRestrictedLockUtils",
+        "SettingsLibAppPreference",
     ],
 
     // ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_SHARED_JAVA_LIBRARIES
diff --git a/packages/SettingsLib/AppPreference/Android.bp b/packages/SettingsLib/AppPreference/Android.bp
new file mode 100644
index 0000000..b56181d
--- /dev/null
+++ b/packages/SettingsLib/AppPreference/Android.bp
@@ -0,0 +1,13 @@
+android_library {
+    name: "SettingsLibAppPreference",
+
+    srcs: ["src/**/*.java"],
+    resource_dirs: ["res"],
+
+    libs: [
+        "androidx.annotation_annotation",
+        "androidx.preference_preference",
+    ],
+    sdk_version: "system_current",
+    min_sdk_version: "21",
+}
diff --git a/packages/SettingsLib/AppPreference/AndroidManifest.xml b/packages/SettingsLib/AppPreference/AndroidManifest.xml
new file mode 100644
index 0000000..7e71308
--- /dev/null
+++ b/packages/SettingsLib/AppPreference/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.settingslib.widget.apppreference">
+
+    <uses-sdk android:minSdkVersion="21" />
+
+</manifest>
diff --git a/packages/SettingsLib/AppPreference/res/layout/preference_app.xml b/packages/SettingsLib/AppPreference/res/layout/preference_app.xml
new file mode 100644
index 0000000..6d35550
--- /dev/null
+++ b/packages/SettingsLib/AppPreference/res/layout/preference_app.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="?android:attr/selectableItemBackground"
+    android:gravity="center_vertical"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+    <LinearLayout
+        android:id="@+id/icon_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:gravity="start|center_vertical"
+        android:minWidth="56dp"
+        android:orientation="horizontal"
+        android:paddingEnd="8dp"
+        android:paddingTop="4dp"
+        android:paddingBottom="4dp">
+        <ImageView
+            android:id="@android:id/icon"
+            android:layout_width="@dimen/secondary_app_icon_size"
+            android:layout_height="@dimen/secondary_app_icon_size"/>
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:paddingTop="16dp"
+        android:paddingBottom="16dp">
+
+        <TextView android:id="@android:id/title"
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:singleLine="true"
+                  android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+                  android:ellipsize="marquee"
+                  android:fadingEdge="horizontal"/>
+
+        <LinearLayout
+            android:id="@+id/summary_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:visibility="gone">
+            <TextView android:id="@android:id/summary"
+                      android:layout_width="0dp"
+                      android:layout_height="wrap_content"
+                      android:layout_weight="1"
+                      android:textAppearance="@android:style/TextAppearance.Material.Small"
+                      android:textAlignment="viewStart"
+                      android:textColor="?android:attr/textColorSecondary"/>
+
+            <TextView android:id="@+id/appendix"
+                      android:layout_width="0dp"
+                      android:layout_height="wrap_content"
+                      android:layout_weight="1"
+                      android:textAppearance="@android:style/TextAppearance.Material.Small"
+                      android:textAlignment="viewEnd"
+                      android:textColor="?android:attr/textColorSecondary"
+                      android:maxLines="1"
+                      android:ellipsize="end"/>
+        </LinearLayout>
+        <ProgressBar
+            android:id="@android:id/progress"
+            style="?android:attr/progressBarStyleHorizontal"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="4dp"
+            android:max="100"
+            android:visibility="gone"/>
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@android:id/widget_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:gravity="center"
+        android:minWidth="64dp"
+        android:orientation="vertical"/>
+
+</LinearLayout>
diff --git a/packages/SettingsLib/AppPreference/res/values/dimens.xml b/packages/SettingsLib/AppPreference/res/values/dimens.xml
new file mode 100644
index 0000000..e2a7a19
--- /dev/null
+++ b/packages/SettingsLib/AppPreference/res/values/dimens.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <dimen name="secondary_app_icon_size">32dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/AppPreference/src/com/android/settingslib/widget/apppreference/AppPreference.java b/packages/SettingsLib/AppPreference/src/com/android/settingslib/widget/apppreference/AppPreference.java
new file mode 100644
index 0000000..593b6f5
--- /dev/null
+++ b/packages/SettingsLib/AppPreference/src/com/android/settingslib/widget/apppreference/AppPreference.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.widget.apppreference;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ProgressBar;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+public class AppPreference extends Preference {
+
+    private int mProgress;
+    private boolean mProgressVisible;
+
+    public AppPreference(Context context) {
+        super(context);
+        setLayoutResource(R.layout.preference_app);
+    }
+
+    public AppPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setLayoutResource(R.layout.preference_app);
+    }
+
+    public void setProgress(int amount) {
+        mProgress = amount;
+        mProgressVisible = true;
+        notifyChanged();
+    }
+
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder view) {
+        super.onBindViewHolder(view);
+
+        view.findViewById(R.id.summary_container)
+                .setVisibility(TextUtils.isEmpty(getSummary()) ? View.GONE : View.VISIBLE);
+        final ProgressBar progress = (ProgressBar) view.findViewById(android.R.id.progress);
+        if (mProgressVisible) {
+            progress.setProgress(mProgress);
+            progress.setVisibility(View.VISIBLE);
+        } else {
+            progress.setVisibility(View.GONE);
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/HelpUtils/res/values-ml/strings.xml b/packages/SettingsLib/HelpUtils/res/values-ml/strings.xml
index d2a7452..731257e 100644
--- a/packages/SettingsLib/HelpUtils/res/values-ml/strings.xml
+++ b/packages/SettingsLib/HelpUtils/res/values-ml/strings.xml
@@ -17,5 +17,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="help_feedback_label" msgid="4550436169116444686">"സഹായം &amp; ഫീഡ്‌ബാക്ക്"</string>
+    <string name="help_feedback_label" msgid="4550436169116444686">"സഹായവും ഫീഡ്‌ബാക്കും"</string>
 </resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values/strings.xml b/packages/SettingsLib/HelpUtils/res/values/strings.xml
index ae07f5d..3e882bc 100644
--- a/packages/SettingsLib/HelpUtils/res/values/strings.xml
+++ b/packages/SettingsLib/HelpUtils/res/values/strings.xml
@@ -17,7 +17,7 @@
 
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
 
-    <!-- Label for Help and feedback menu item -->
+    <!-- Label for Help and feedback menu item [CHAR LIMIT=45]-->
     <string name="help_feedback_label">Help &amp; feedback</string>
 
 </resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/RestrictedLockUtils/Android.bp b/packages/SettingsLib/RestrictedLockUtils/Android.bp
index d4c9794..b2f0882 100644
--- a/packages/SettingsLib/RestrictedLockUtils/Android.bp
+++ b/packages/SettingsLib/RestrictedLockUtils/Android.bp
@@ -2,6 +2,7 @@
     name: "SettingsLibRestrictedLockUtils",
 
     srcs: ["src/**/*.java"],
+    resource_dirs: ["res"],
 
     libs: [
         "androidx.annotation_annotation",
diff --git a/packages/SettingsLib/res/layout/restricted_icon.xml b/packages/SettingsLib/RestrictedLockUtils/res/layout/restricted_icon.xml
similarity index 76%
rename from packages/SettingsLib/res/layout/restricted_icon.xml
rename to packages/SettingsLib/RestrictedLockUtils/res/layout/restricted_icon.xml
index 724a524..0f02abd 100644
--- a/packages/SettingsLib/res/layout/restricted_icon.xml
+++ b/packages/SettingsLib/RestrictedLockUtils/res/layout/restricted_icon.xml
@@ -15,6 +15,7 @@
 -->
 <ImageView xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/restricted_icon"
-    android:layout_width="@dimen/restricted_icon_size"
-    android:layout_height="@dimen/restricted_icon_size"
-    android:src="@drawable/ic_info" />
\ No newline at end of file
+    android:layout_width="@*android:dimen/config_restricted_icon_size"
+    android:layout_height="@*android:dimen/config_restricted_icon_size"
+    android:tint="?android:attr/colorAccent"
+    android:src="@*android:drawable/ic_info" />
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-af/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-af/strings.xml
new file mode 100644
index 0000000..dced02c
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-af/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Geaktiveer deur administrateur"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Gedeaktiveer deur administrateur"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-am/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-am/strings.xml
new file mode 100644
index 0000000..d13be0c
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-am/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"በአስተዳዳሪ ነቅቷል"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"በአስተዳዳሪ ተሰናክሏል"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ar/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ar/strings.xml
new file mode 100644
index 0000000..15c0010
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ar/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"فعَّل المشرف هذا الإعداد."</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"أوقف المشرف هذا الإعداد."</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-as/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-as/strings.xml
new file mode 100644
index 0000000..7a3b8e4
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-as/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"প্ৰশাসকে সক্ষম কৰিছে"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"প্ৰশাসকে অক্ষম কৰিছে"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-az/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-az/strings.xml
new file mode 100644
index 0000000..d1434bd
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-az/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Admin tərəfindən aktiv edildi"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Admin tərəfindən deaktiv edildi"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..ee61192
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Administrator je omogućio"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Administrator je onemogućio"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-be/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-be/strings.xml
new file mode 100644
index 0000000..2d13d45
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-be/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Уключана адміністратарам"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Адключана адміністратарам"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-bg/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-bg/strings.xml
new file mode 100644
index 0000000..361910c
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-bg/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Активирано от администратора"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Деактивирано от администратора"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-bn/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-bn/strings.xml
new file mode 100644
index 0000000..7609166
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-bn/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"অ্যাডমিন চালু করেছেন"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"অ্যাডমিন বন্ধ করেছেন"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-bs/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-bs/strings.xml
new file mode 100644
index 0000000..9704095
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-bs/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Omogućio administrator"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Onemogućio administrator"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ca/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ca/strings.xml
new file mode 100644
index 0000000..5569664
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ca/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Activat per l\'administrador"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Desactivat per l\'administrador"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-cs/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-cs/strings.xml
new file mode 100644
index 0000000..f8120aa
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-cs/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Zapnuto administrátorem"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Vypnuto administrátorem"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-da/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-da/strings.xml
new file mode 100644
index 0000000..d75f27b
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-da/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Aktiveret af administratoren"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Deaktiveret af administratoren"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-de/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-de/strings.xml
new file mode 100644
index 0000000..3ef46d9
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-de/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Vom Administrator aktiviert"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Vom Administrator deaktiviert"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-el/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-el/strings.xml
new file mode 100644
index 0000000..643686e
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-el/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Ενεργοποιήθηκε από τον διαχειριστή"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Απενεργοποιήθηκε από τον διαχειριστή"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-en-rAU/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..69c0bc3
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-en-rAU/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Enabled by admin"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Disabled by admin"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-en-rCA/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..69c0bc3
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-en-rCA/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Enabled by admin"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Disabled by admin"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-en-rGB/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..69c0bc3
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-en-rGB/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Enabled by admin"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Disabled by admin"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-en-rIN/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..69c0bc3
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-en-rIN/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Enabled by admin"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Disabled by admin"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-en-rXC/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..f329a76
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-en-rXC/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‏‎‎‏‏‎‏‎‏‏‏‎‎‏‎‏‎‏‎‏‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‎‎‎‎‎Enabled by admin‎‏‎‎‏‎"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‏‎‏‎‎‎‎‏‎‎‏‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‎‎‎‏‎‎‎‎‏‎‎‎‏‏‎‎‎‏‎‎‎‎‏‎Disabled by admin‎‏‎‎‏‎"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-es-rUS/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..451ea35
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-es-rUS/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"El administrador habilitó la opción"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"El administrador inhabilitó la opción"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-es/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-es/strings.xml
new file mode 100644
index 0000000..3407d13
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-es/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Habilitada por el administrador"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Inhabilitada por el administrador"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-et/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-et/strings.xml
new file mode 100644
index 0000000..98bad62
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-et/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Administraatori lubatud"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Administraatori keelatud"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-eu/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-eu/strings.xml
new file mode 100644
index 0000000..1641a31
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-eu/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Administratzaileak gaitu egin du"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Administratzaileak desgaitu egin du"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-fa/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-fa/strings.xml
new file mode 100644
index 0000000..f4c8334
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-fa/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"فعال‌شده توسط سرپرست"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"غیرفعال‌شده توسط سرپرست"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-fi/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-fi/strings.xml
new file mode 100644
index 0000000..dd62c1a
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-fi/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Järjestelmänvalvojan sallima"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Järjestelmänvalvojan estämä"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-fr-rCA/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..85ec907
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-fr-rCA/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Activé par l\'administrateur"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Désactivé par l\'administrateur"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-fr/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-fr/strings.xml
new file mode 100644
index 0000000..85ec907
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-fr/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Activé par l\'administrateur"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Désactivé par l\'administrateur"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-gl/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-gl/strings.xml
new file mode 100644
index 0000000..0d67cc2
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-gl/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Opción activada polo administrador"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Opción desactivada polo administrador"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-gu/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-gu/strings.xml
new file mode 100644
index 0000000..076c1be
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-gu/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"વ્યવસ્થાપકે ચાલુ કરેલ"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"વ્યવસ્થાપકે બંધ કરેલ"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-hi/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-hi/strings.xml
new file mode 100644
index 0000000..75d103f
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-hi/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"एडमिन की ओर से चालू किया गया"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"एडमिन की ओर से बंद किया गया"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-hr/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-hr/strings.xml
new file mode 100644
index 0000000..9704095
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-hr/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Omogućio administrator"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Onemogućio administrator"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-hu/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-hu/strings.xml
new file mode 100644
index 0000000..be1cb97
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-hu/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"A rendszergazda bekapcsolta"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"A rendszergazda kikapcsolta"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-hy/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-hy/strings.xml
new file mode 100644
index 0000000..78dab28
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-hy/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Միացված է ադմինիստրատորի կողմից"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Անջատվել է ադմինիստրատորի կողմից"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-in/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-in/strings.xml
new file mode 100644
index 0000000..824ddde
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-in/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Diaktifkan oleh admin"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Dinonaktifkan oleh admin"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-is/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-is/strings.xml
new file mode 100644
index 0000000..0707a67
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-is/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Gert virkt af kerfisstjóra"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Gert óvirkt af kerfisstjóra"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-it/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-it/strings.xml
new file mode 100644
index 0000000..084a47b
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-it/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Attivata dall\'amministratore"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Disattivata dall\'amministratore"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-iw/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-iw/strings.xml
new file mode 100644
index 0000000..fca5986
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-iw/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"מופעל על ידי מנהל המכשיר"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"הושבת על ידי מנהל המכשיר"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ja/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ja/strings.xml
new file mode 100644
index 0000000..1c077b6
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ja/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"管理者が有効にしました"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"管理者が無効にしました"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ka/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ka/strings.xml
new file mode 100644
index 0000000..9ecf6b3
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ka/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"ჩართულია ადმინისტრატორის მიერ"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"გათიშულია ადმინისტრატორის მიერ"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-kk/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-kk/strings.xml
new file mode 100644
index 0000000..552e02e
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-kk/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Әкімші қосқан"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Әкімші өшірген"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-km/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-km/strings.xml
new file mode 100644
index 0000000..aff5d30
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-km/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"បើកដោយ​អ្នកគ្រប់គ្រង"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"បិទដោយអ្នកគ្រប់គ្រង"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-kn/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-kn/strings.xml
new file mode 100644
index 0000000..99bd4d5
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-kn/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"ನಿರ್ವಾಹಕರು ಸಕ್ರಿಯಗೊಳಿಸಿದ್ದಾರೆ"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"ನಿರ್ವಾಹಕರು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿದ್ದಾರೆ"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ko/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ko/strings.xml
new file mode 100644
index 0000000..d7b0b44
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ko/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"관리자가 사용 설정함"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"관리자가 사용 중지함"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ky/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ky/strings.xml
new file mode 100644
index 0000000..df3b559
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ky/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Администратор иштетип койгон"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Администратор өчүрүп койгон"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-lo/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-lo/strings.xml
new file mode 100644
index 0000000..fca6d1b
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-lo/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"ເປີດນຳໃຊ້ໂດຍຜູ້ເບິ່ງແຍງລະບົບ"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"ຖືກຜູ້ເບິ່ງແຍງລະບົບປິດໄວ້"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-lt/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-lt/strings.xml
new file mode 100644
index 0000000..0bd27bc
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-lt/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Įgalino administratorius"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Išjungė administratorius"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-lv/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-lv/strings.xml
new file mode 100644
index 0000000..9c5f693
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-lv/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Iespējoja administrators"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Atspējoja administrators"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-mk/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-mk/strings.xml
new file mode 100644
index 0000000..b0fb0a8
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-mk/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Овозможено од администраторот"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Оневозможено од администраторот"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ml/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ml/strings.xml
new file mode 100644
index 0000000..dd9c229
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ml/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"അഡ്‌മിൻ പ്രവർത്തനക്ഷമമാക്കി"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"അഡ്‌മിൻ പ്രവർത്തനരഹിതമാക്കി"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-mn/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-mn/strings.xml
new file mode 100644
index 0000000..d32c2ca
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-mn/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Админ идэвхжүүлсэн"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Админ цуцалсан"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-mr/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-mr/strings.xml
new file mode 100644
index 0000000..06fdf6f
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-mr/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"प्रशासकाने सुरू केलेले"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"प्रशासकाने बंद केलेले"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ms/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ms/strings.xml
new file mode 100644
index 0000000..aabfb7c
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ms/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Didayakan oleh pentadbir"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Dilumpuhkan oleh pentadbir"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-my/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-my/strings.xml
new file mode 100644
index 0000000..daa4614
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-my/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"စီမံခန့်ခွဲသူက ဖွင့်ထားသည်"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"စီမံခန့်ခွဲသူက ပိတ်ထားသည်"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-nb/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-nb/strings.xml
new file mode 100644
index 0000000..becbb91
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-nb/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Aktivert av administratoren"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Deaktivert av administratoren"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ne/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ne/strings.xml
new file mode 100644
index 0000000..63ef646
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ne/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"प्रशासकद्वारा सक्षम पारिएको"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"प्रशासकद्वारा असक्षम पारिएको"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-nl/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-nl/strings.xml
new file mode 100644
index 0000000..5d7a85e
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-nl/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Ingeschakeld door beheerder"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Uitgeschakeld door beheerder"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-or/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-or/strings.xml
new file mode 100644
index 0000000..fee0d39
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-or/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"ବ୍ୟବସ୍ଥାପକଙ୍କ ଦ୍ୱାରା ସକ୍ଷମ କରାଯାଇଛି"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"ବ୍ୟବସ୍ଥାପକଙ୍କ ଦ୍ଵାରା ଅକ୍ଷମ କରାଯାଇଛି"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-pa/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-pa/strings.xml
new file mode 100644
index 0000000..2765cabd
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-pa/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਚਾਲੂ ਕੀਤਾ ਗਿਆ"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਬੰਦ ਕੀਤਾ ਗਿਆ"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-pl/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-pl/strings.xml
new file mode 100644
index 0000000..d9e06b6
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-pl/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Włączone przez administratora"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Wyłączone przez administratora"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-pt-rBR/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..1ad4b6b
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-pt-rBR/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Ativado pelo administrador"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Desativado pelo administrador"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-pt-rPT/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..f86a73f
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-pt-rPT/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Ativada pelo administrador"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Desativada pelo administrador"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-pt/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-pt/strings.xml
new file mode 100644
index 0000000..1ad4b6b
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-pt/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Ativado pelo administrador"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Desativado pelo administrador"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ro/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ro/strings.xml
new file mode 100644
index 0000000..ff8c2aa
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ro/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Activat de administrator"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Dezactivat de administrator"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ru/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ru/strings.xml
new file mode 100644
index 0000000..d4dfb1c
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ru/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Включено администратором"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Отключено администратором"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-si/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-si/strings.xml
new file mode 100644
index 0000000..7c8520b
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-si/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"පරිපාලක විසින් සබල කර ඇත"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"ඔබගේ පරිපාලක විසින් අබල කර ඇත"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-sk/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-sk/strings.xml
new file mode 100644
index 0000000..7a9c1cc
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-sk/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Povolené správcom"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Zakázané správcom"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-sl/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-sl/strings.xml
new file mode 100644
index 0000000..4926641
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-sl/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Omogočil skrbnik"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Onemogočil skrbnik"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-sq/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-sq/strings.xml
new file mode 100644
index 0000000..5f9dc59
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-sq/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Aktivizuar nga administratori"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Çaktivizuar nga administratori"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-sr/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-sr/strings.xml
new file mode 100644
index 0000000..2d1ac54
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-sr/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Администратор је омогућио"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Администратор је онемогућио"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-sv/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-sv/strings.xml
new file mode 100644
index 0000000..6af3776
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-sv/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Aktiverad av administratör"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Inaktiverad av administratören"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-sw/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-sw/strings.xml
new file mode 100644
index 0000000..08526f8
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-sw/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Imewashwa na msimamizi"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Imezimwa na msimamizi"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ta/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ta/strings.xml
new file mode 100644
index 0000000..405fb7c
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ta/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"நிர்வாகி இயக்கியுள்ளார்"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"நிர்வாகி முடக்கியுள்ளார்"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-te/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-te/strings.xml
new file mode 100644
index 0000000..462f02e
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-te/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"నిర్వాహకులు ప్రారంభించారు"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"నిర్వాహకులు నిలిపివేసారు"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-th/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-th/strings.xml
new file mode 100644
index 0000000..e654ba1
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-th/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"เปิดใช้โดยผู้ดูแลระบบ"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"ปิดใช้โดยผู้ดูแลระบบ"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-tl/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-tl/strings.xml
new file mode 100644
index 0000000..f80cefa
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-tl/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Na-enable ng admin"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Na-disable ng admin"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-tr/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-tr/strings.xml
new file mode 100644
index 0000000..9dd4713
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-tr/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Yönetici tarafından etkinleştirildi"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Yönetici tarafından devre dışı bırakıldı"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-uk/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-uk/strings.xml
new file mode 100644
index 0000000..5096921
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-uk/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Увімкнено адміністратором"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Вимкнено адміністратором"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ur/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ur/strings.xml
new file mode 100644
index 0000000..7e70936
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ur/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"منتظم کی طرف سے فعال کردہ"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"منتظم کی طرف سے غیر فعال کردہ"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-uz/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-uz/strings.xml
new file mode 100644
index 0000000..a402af6
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-uz/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Administrator tomonidan yoqilgan"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Administrator tomonidan faolsizlantirilgan"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-vi/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-vi/strings.xml
new file mode 100644
index 0000000..dd993df
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-vi/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Do quản trị viên bật"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Bị quản trị viên tắt"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rCN/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..2aab9ac
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rCN/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"已被管理员启用"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"已被管理员停用"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rHK/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..cb3163a
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rHK/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"已由管理員啟用"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"已由管理員停用"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rTW/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..cb3163a
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rTW/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"已由管理員啟用"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"已由管理員停用"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-zu/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-zu/strings.xml
new file mode 100644
index 0000000..313c9eb
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-zu/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="enabled_by_admin" msgid="7797093432952898000">"Kunikwe amandla umlawuli"</string>
+    <string name="disabled_by_admin" msgid="1910810467107358241">"Kukhutshazwe umlawuli"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values/strings.xml
new file mode 100644
index 0000000..7e4460b
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Summary for switch preference to denote it is switched on [CHAR LIMIT=50] -->
+    <string name="enabled_by_admin">Enabled by admin</string>
+    <!-- Summary for switch preference to denote it is switched off [CHAR LIMIT=50] -->
+    <string name="disabled_by_admin">Disabled by admin</string>
+
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/layout/restricted_switch_widget.xml b/packages/SettingsLib/res/layout/restricted_switch_widget.xml
index b286df0..e1f6cdf 100644
--- a/packages/SettingsLib/res/layout/restricted_switch_widget.xml
+++ b/packages/SettingsLib/res/layout/restricted_switch_widget.xml
@@ -16,9 +16,10 @@
 <merge xmlns:android="http://schemas.android.com/apk/res/android">
     <ImageView xmlns:android="http://schemas.android.com/apk/res/android"
         android:id="@+id/restricted_icon"
-        android:layout_width="@dimen/restricted_icon_size"
-        android:layout_height="@dimen/restricted_icon_size"
-        android:src="@drawable/ic_info"
+        android:layout_width="@*android:dimen/config_restricted_icon_size"
+        android:layout_height="@*android:dimen/config_restricted_icon_size"
+        android:tint="?android:attr/colorAccent"
+        android:src="@*android:drawable/ic_info"
         android:gravity="end|center_vertical" />
     <!-- Based off frameworks/base/core/res/res/layout/preference_widget_switch.xml -->
     <Switch xmlns:android="http://schemas.android.com/apk/res/android"
@@ -28,4 +29,4 @@
         android:focusable="false"
         android:clickable="false"
         android:background="@null" />
-</merge>
\ No newline at end of file
+</merge>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index aa96444..b77d4e5 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Ingeprop; kan nie op die oomblik laai nie"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Vol"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Beheer deur administrateur"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Geaktiveer deur administrateur"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Gedeaktiveer deur administrateur"</string>
     <string name="disabled" msgid="9206776641295849915">"Gedeaktiveer"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Toegelaat"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Nie toegelaat nie"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 452206c..836ec80 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"ተሰክቷል፣ አሁን ኃይል መሙላት አይቻልም"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"ሙሉነው"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"በአስተዳዳሪ ቁጥጥር የተደረገበት"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"በአስተዳዳሪ ነቅቷል"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"በአስተዳዳሪ ተሰናክሏል"</string>
     <string name="disabled" msgid="9206776641295849915">"ቦዝኗል"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"ይፈቀዳል"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"አይፈቀድም"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index e67e1ec..5c11db1 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"تم التوصيل، ولكن يتعذّر الشحن الآن"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"ممتلئة"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"إعدادات يتحكم فيها المشرف"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"تم تفعيل الإعداد بواسطة المشرف"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"تم إيقاف الإعداد بواسطة المشرف"</string>
     <string name="disabled" msgid="9206776641295849915">"غير مفعّل"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"مسموح به"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"غير مسموح به"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 7311661..ddd17daf 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"প্লাগ কৰি থোৱা হৈছে, এই মুহূৰ্তত চ্চাৰ্জ কৰিব নোৱাৰি"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"পূৰ্ণ"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"এডমিনৰ দ্বাৰা নিয়ন্ত্ৰিত"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"প্ৰশাসকে সক্ষম কৰিছে"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"এডমিনে অক্ষম কৰিছে ৰাখিছে"</string>
     <string name="disabled" msgid="9206776641295849915">"নিষ্ক্ৰিয়"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"অনুমতি দিয়া হৈছে"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"অনুমতি দিয়া হোৱা নাই"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 750bf5d..a6e484f 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Cihaz hazırda batareya yığa bilmir"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Tam"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Admin tərəfindən nəzarət olunur"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Admin tərəfindən aktiv edildi"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Admin tərəfindən deaktiv edildi"</string>
     <string name="disabled" msgid="9206776641295849915">"Deaktiv"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"İcazə verilib"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"İcazə verilməyib"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index cd8096c..a446845 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Priključeno je, ali punjenje trenutno nije moguće"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Puna"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontroliše administrator"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Omogućio je administrator"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Administrator je onemogućio"</string>
     <string name="disabled" msgid="9206776641295849915">"Onemogućeno"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Dozvoljeno"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Nije dozvoljeno"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 072913a..d56db13 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Падключана да сеткі сілкавання, зарадзіць зараз немагчыма"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Поўная"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Кантралюецца адміністратарам"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Уключана адміністратарам"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Адключана адміністратарам"</string>
     <string name="disabled" msgid="9206776641295849915">"Адключанае"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Дазволена"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Забаронена"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index a5ce523..c1bc31c 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Включена в захранването, в момента не се зарежда"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Пълна"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Контролира се от администратор"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Активирано от администратора"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Деактивирано от администратора"</string>
     <string name="disabled" msgid="9206776641295849915">"Деактивирано"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Има разрешение"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Няма разрешение"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index c053771..1550c00 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"প্লাগ-ইন করা হয়েছে কিন্তু এখনই চার্জ করা যাবে না"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"পূর্ণ"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"প্রশাসকের দ্বারা নিয়ন্ত্রিত"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"প্রশাসক দ্বারা সক্ষম করা হয়েছে"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"প্রশাসক দ্বারা অক্ষম করা হয়েছে"</string>
     <string name="disabled" msgid="9206776641295849915">"অক্ষম হয়েছে"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"অনুমোদিত"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"অনুমোদিত নয়"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 764bc19..460e7cf 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Priključen, trenutno se ne može puniti"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Puna"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Pod kontrolom administratora"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Omogućio administrator"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Onemogućio administrator"</string>
     <string name="disabled" msgid="9206776641295849915">"Onemogućeno"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Dozvoljeno"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Nije dozvoljeno"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 8309c41a..72dd8cf 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"El dispositiu està endollat però en aquests moments no es pot carregar"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Plena"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlat per l\'administrador"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Activada per l\'administrador"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Desactivada per l\'administrador"</string>
     <string name="disabled" msgid="9206776641295849915">"Desactivat"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Amb permís"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Sense permís"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index bd8bc2b..de02245 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Zapojeno, ale nelze nabíjet"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Nabitá"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Spravováno administrátorem"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Zapnuto administrátorem"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Zakázáno administrátorem"</string>
     <string name="disabled" msgid="9206776641295849915">"Deaktivováno"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Povoleno"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Není povoleno"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index ab81346..34608d3 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Enheden er tilsluttet en strømkilde. Det er ikke muligt at oplade på nuværende tidspunkt."</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Fuldt"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrolleret af administratoren"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Aktiveret af administratoren"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Deaktiveret af administratoren"</string>
     <string name="disabled" msgid="9206776641295849915">"Deaktiveret"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Tilladt"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Ikke tilladt"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 2432a10..79965d2 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -348,7 +348,7 @@
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Momentan ausgeführte Dienste anzeigen und steuern"</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-Implementierung"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView-Implementierung festlegen"</string>
-    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Diese Auswahl ist nicht mehr gültig. Versuche es erneut."</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Diese Auswahl ist nicht mehr gültig. Bitte versuche es noch einmal."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Zu Dateiverschlüsselung wechseln"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Wechseln…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Dateiverschlüsselung wird bereits verwendet."</string>
@@ -379,12 +379,12 @@
     <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Weniger als <xliff:g id="THRESHOLD">%1$s</xliff:g> verbleibend (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Mehr als <xliff:g id="TIME_REMAINING">%1$s</xliff:g> verbleibend (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_only_more_than_subtext" msgid="8931654680569617380">"Mehr als <xliff:g id="TIME_REMAINING">%1$s</xliff:g> verbleibend"</string>
-    <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="1181059207608751924">"Smartphone wird möglicherweise bald ausgeschaltet"</string>
-    <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="2606370266981054691">"Tablet wird möglicherweise bald ausgeschaltet"</string>
-    <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="2918084807716859985">"Gerät wird möglicherweise bald ausgeschaltet"</string>
-    <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="3090926004324573908">"Smartphone wird möglicherweise bald ausgeschaltet (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
-    <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="7466484148515796216">"Tablet wird möglicherweise bald ausgeschaltet (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
-    <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="603933521600231649">"Gerät wird möglicherweise bald ausgeschaltet (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
+    <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="1181059207608751924">"Smartphone wird eventuell bald ausgeschaltet"</string>
+    <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="2606370266981054691">"Tablet wird eventuell bald ausgeschaltet"</string>
+    <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="2918084807716859985">"Gerät wird eventuell bald ausgeschaltet"</string>
+    <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="3090926004324573908">"Smartphone wird eventuell bald ausgeschaltet (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
+    <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="7466484148515796216">"Tablet wird eventuell bald ausgeschaltet (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
+    <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="603933521600231649">"Gerät wird eventuell bald ausgeschaltet (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> bis zur vollständigen Aufladung"</string>
     <string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> bis vollständig geladen"</string>
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Angeschlossen, kann derzeit nicht geladen werden"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Voll"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Durch den Administrator verwaltet"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Vom Administrator aktiviert"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Vom Administrator deaktiviert"</string>
     <string name="disabled" msgid="9206776641295849915">"Deaktiviert"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Zulässig"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Nicht zulässig"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 6f2889c..b9ea843 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Συνδέθηκε, δεν είναι δυνατή η φόρτιση αυτήν τη στιγμή"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Πλήρης"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Ελέγχονται από το διαχειριστή"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Ενεργοποιήθηκε από τον διαχειριστή"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Απενεργοποιήθηκε από τον διαχειριστή"</string>
     <string name="disabled" msgid="9206776641295849915">"Απενεργοποιημένο"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Επιτρέπεται"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Δεν επιτρέπεται"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 154aa7d..1a7d7c5 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Plugged in, can\'t charge right now"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Full"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlled by admin"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Enabled by admin"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Disabled by admin"</string>
     <string name="disabled" msgid="9206776641295849915">"Disabled"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Allowed"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Not allowed"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 154aa7d..1a7d7c5 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Plugged in, can\'t charge right now"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Full"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlled by admin"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Enabled by admin"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Disabled by admin"</string>
     <string name="disabled" msgid="9206776641295849915">"Disabled"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Allowed"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Not allowed"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 154aa7d..1a7d7c5 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Plugged in, can\'t charge right now"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Full"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlled by admin"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Enabled by admin"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Disabled by admin"</string>
     <string name="disabled" msgid="9206776641295849915">"Disabled"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Allowed"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Not allowed"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 154aa7d..1a7d7c5 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Plugged in, can\'t charge right now"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Full"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlled by admin"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Enabled by admin"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Disabled by admin"</string>
     <string name="disabled" msgid="9206776641295849915">"Disabled"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Allowed"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Not allowed"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index e9746c0..2bfd5b1 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‏‎‏‏‎‎‎‏‏‏‏‏‏‎‎‏‏‏‏‎‎‎‎‎‏‎‎‎‎‏‏‏‏‏‎‎‎‏‎‏‏‏‎‏‏‎‎‏‏‎Plugged in, can\'t charge right now‎‏‎‎‏‎"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‏‏‏‎‎‏‏‎‎‏‏‎‎‎‎‏‏‎‎‎‎‏‎‎‏‏‏‎‎‏‏‎‏‏‏‎‎‏‏‏‏‎‏‎‏‏‎‏‎‏‏‎‎‎‏‏‎‎‎‎Full‎‏‎‎‏‎"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‎‏‏‏‎‏‎‏‎‎‏‎‎‏‎‏‎‏‏‏‏‎‏‏‏‎‎‎‏‏‎‏‎‏‏‎‎‏‏‎‎‏‏‏‎‎‎‎‏‏‎‎‏‎Controlled by admin‎‏‎‎‏‎"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‎‎‏‎‏‎‎‎‎‏‎‎‎‎‎‎‎‏‏‏‎‎‏‎‎‎‎‏‏‏‏‏‎Enabled by admin‎‏‎‎‏‎"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‎‏‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‎‏‎‎‎‏‎‏‎‎‎‏‏‎‏‎‏‏‏‎‏‏‎‏‏‏‎‏‏‎‎‎Disabled by admin‎‏‎‎‏‎"</string>
     <string name="disabled" msgid="9206776641295849915">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‎‎‎‏‎‏‎‏‎‎‏‎‎‏‏‎‏‎‏‏‏‏‎‏‏‎‎‏‏‎‏‏‎‎‏‏‎‎‏‏‎‏‏‏‎‏‏‎Disabled‎‏‎‎‏‎"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‏‎‏‎‎‏‎‏‏‏‏‎‎‎‏‎‎‎‎‎‏‏‏‎‎‎‎‏‎‎‏‎‏‎‏‏‏‏‎‎‏‏‎‏‎‏‏‏‎‎‏‎‏‎Allowed‎‏‎‎‏‎"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‏‎‏‎‎‏‎‏‎‎‎‎‎‏‎‏‏‏‏‏‏‎‎‎‏‏‏‎‏‏‎‎‎‎‎‏‎‎‏‏‏‎‎‎‎‎‎‏‏‎‎‎‎‏‏‎‏‏‎‎Not allowed‎‏‎‎‏‎"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 706e1d3..790c0d3 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Conectado. No se puede cargar en este momento"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Cargado"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlada por el administrador"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"El administrador habilitó esta opción"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"El administrador inhabilitó esta opción"</string>
     <string name="disabled" msgid="9206776641295849915">"Inhabilitada"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Permitida"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"No permitida"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index f9eddd9..1dec85d 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Se ha conectado, pero no se puede cargar en este momento"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Completa"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlada por el administrador"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Habilitada por el administrador"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Inhabilitado por el administrador"</string>
     <string name="disabled" msgid="9206776641295849915">"Inhabilitada"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Autorizadas"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"No autorizadas"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index ac31880..406e15d 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Vooluvõrgus, praegu ei saa laadida"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Täis"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Juhib administraator"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Administraatori lubatud"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Administraatori keelatud"</string>
     <string name="disabled" msgid="9206776641295849915">"Keelatud"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Lubatud"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Pole lubatud"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 2eee948..bd4724e 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Konektatuta dago. Ezin da kargatu une honetan."</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Beteta"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Administratzaileak kontrolatzen du"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Administratzaileak gaitu du"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Administratzaileak desgaitu du"</string>
     <string name="disabled" msgid="9206776641295849915">"Desgaituta"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Baimena dauka"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Ez dauka baimenik"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 6efd4fe..45b8ac7 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"به برق وصل شده‌ است، درحال‌حاضر شارژ نمی‌شود"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"پر"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"توسط سرپرست سیستم کنترل می‌شود"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"فعال‌شده توسط سرپرست"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"غیرفعال‌شده توسط سرپرست"</string>
     <string name="disabled" msgid="9206776641295849915">"غیر فعال شد"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"مجاز"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"مجاز نیست"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 4d64e81..23c63b1 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Kytketty virtalähteeseen, lataaminen ei onnistu"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Täynnä"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Järjestelmänvalvoja hallinnoi tätä asetusta."</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Järjestelmänvalvojan käyttöön ottama"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Järjestelmänvalvojan estämä"</string>
     <string name="disabled" msgid="9206776641295849915">"Pois käytöstä"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Sallittu"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Ei sallittu"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 8e813ea..ad99000 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"L\'appareil est branché, mais il ne peut pas être chargé pour le moment"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Pleine"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Contrôlé par l\'administrateur"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Activé par l\'administrateur"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Désactivé par l\'administrateur"</string>
     <string name="disabled" msgid="9206776641295849915">"Désactivée"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Autorisée"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Non autorisée"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index baf8ed0..c23db25 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Appareil branché, mais impossible de le charger pour le moment"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"pleine"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Contrôlé par l\'administrateur"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Activé par l\'administrateur"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Désactivé par l\'administrateur"</string>
     <string name="disabled" msgid="9206776641295849915">"Désactivée"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Autorisé"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Non autorisé"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index dc22b25..46532e9 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Conectouse, pero non se pode cargar neste momento"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Completa"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Opción controlada polo administrador"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Activado polo administrador"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Desactivado polo administrador"</string>
     <string name="disabled" msgid="9206776641295849915">"Desactivada"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Permitida"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Non permitida"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 7943d51..6a74490 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"પ્લગ ઇન કરેલ, હમણાં ચાર્જ કરી શકતા નથી"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"પૂર્ણ"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"વ્યવસ્થાપક દ્વારા નિયંત્રિત"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"વ્યવસ્થાપકે સક્ષમ કરેલ"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"વ્યવસ્થાપકે અક્ષમ કરેલ"</string>
     <string name="disabled" msgid="9206776641295849915">"અક્ષમ કર્યો"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"મંજૂરી છે"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"મંજૂરી નથી"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 3ec7e58..bd9a6ec 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"प्लग इन है, अभी चार्ज नहीं हो सकती"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"पूरी"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"इसका नियंत्रण एडमिन के पास है"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"व्यवस्थापक ने सक्षम किया है"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"व्यवस्थापक ने अक्षम किया है"</string>
     <string name="disabled" msgid="9206776641295849915">"बंद किया गया"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"अनुमति है"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"अनुमति नहीं है"</string>
@@ -448,7 +446,6 @@
     <string name="alarm_template_far" msgid="3779172822607461675">"अलार्म <xliff:g id="WHEN">%1$s</xliff:g> को बजेगा"</string>
     <string name="zen_mode_duration_settings_title" msgid="229547412251222757">"अवधि"</string>
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"हर बार पूछें"</string>
-    <!-- no translation found for zen_mode_forever (2704305038191592967) -->
-    <skip />
+    <string name="zen_mode_forever" msgid="2704305038191592967">"जब तक आप इसे बंद नहीं करते"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"अभी-अभी"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index ce8e6ec..5270531 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Uključen, trenutačno se ne može puniti"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Puna"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrolira administrator"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Omogućio administrator"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Onemogućio administrator"</string>
     <string name="disabled" msgid="9206776641295849915">"Onemogućeno"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Dopušteno"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Nije dopušteno"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 1c79199..ad897f8 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Csatlakoztatva, jelenleg nem tölt"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Feltöltve"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Rendszergazda által irányítva"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"A rendszergazda bekapcsolta"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"A rendszergazda kikapcsolta"</string>
     <string name="disabled" msgid="9206776641295849915">"Letiltva"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Engedélyezett"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Nem engedélyezett"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 84ee039..82755f9 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Միացված է հոսանքի աղբյուրին, սակայն այս պահին չի կարող լիցքավորվել"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Լիցքավորված է"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Վերահսկվում է ադմինիստրատորի կողմից"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Միացված է ադմինիստրատորի կողմից"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Անջատվել է ադմինիստրատորի կողմից"</string>
     <string name="disabled" msgid="9206776641295849915">"Կասեցված է"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Թույլատրված է"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Արգելված է"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 9356c85..961f892 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Tercolok, tidak dapat mengisi baterai sekarang"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Penuh"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Dikontrol oleh admin"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Diaktifkan oleh admin"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Dinonaktifkan oleh admin"</string>
     <string name="disabled" msgid="9206776641295849915">"Dinonaktifkan"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Diizinkan"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Tidak diizinkan"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index ca5e1f5..759b7ba 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Í sambandi, ekki hægt að hlaða eins og er"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Fullhlaðin"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Stjórnað af kerfisstjóra"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Gert virkt af kerfisstjóra"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Gert óvirkt af kerfisstjóra"</string>
     <string name="disabled" msgid="9206776641295849915">"Óvirkt"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Heimilað"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Ekki heimilað"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 88a5bb8..bd41e28 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Collegato alla corrente. Impossibile caricare al momento"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Carica"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Gestita dall\'amministratore"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Attivata dall\'amministratore"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Disattivata dall\'amministratore"</string>
     <string name="disabled" msgid="9206776641295849915">"Disattivato"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Consentite"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Non consentite"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index cec35cf..5a11e72 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"המכשיר מחובר, אבל לא ניתן לטעון עכשיו"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"מלא"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"נמצא בשליטת מנהל מערכת"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"מופעל על ידי מנהל המכשיר"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"הושבת על ידי מנהל המכשיר"</string>
     <string name="disabled" msgid="9206776641295849915">"מושבת"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"מורשה"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"לא מורשה"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 9cfdadc..f6b81ed 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"接続されていますが、現在、充電できません"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"フル"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"管理者により管理されています"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"管理者により有効にされています"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"管理者により無効にされています"</string>
     <string name="disabled" msgid="9206776641295849915">"無効"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"許可"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"許可しない"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 1083025..d5f5408 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"მიერთებულია, დატენვა ამჟამად ვერ ხერხდება"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"ბატარეა დატენილია"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"იმართება ადმინისტრატორის მიერ"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"ჩართულია ადმინისტრატორის მიერ"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"გათიშულია ადმინისტრატორის მიერ"</string>
     <string name="disabled" msgid="9206776641295849915">"გამორთული"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"დაშვებულია"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"დაუშვებელია"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index a122d91..c3fbfcd 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Қосылған, зарядталмайды"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Толы"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Әкімші басқарады"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Әкімші қосқан"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Әкімші өшірген"</string>
     <string name="disabled" msgid="9206776641295849915">"Өшірілген"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Рұқсат етілген"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Рұқсат етілмеген"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 7ffd766..8e73f81 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"ដោត​សាកថ្ម​រួចហើយ ប៉ុន្តែ​​សាកថ្ម​មិន​ចូលទេឥឡូវនេះ"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"ពេញ"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"គ្រប់គ្រងដោយអ្នកគ្រប់គ្រង"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"បើកដោយ​អ្នកគ្រប់គ្រង"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"បិទដោយអ្នកគ្រប់គ្រង"</string>
     <string name="disabled" msgid="9206776641295849915">"បិទ"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"បាន​អនុញ្ញាត"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"មិន​អនុញ្ញាត​ទេ"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index e12cbd2..ce225ea 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"ಪ್ಲಗ್ ಇನ್ ಮಾಡಲಾಗಿದೆ, ಇದೀಗ ಚಾರ್ಜ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"ಭರ್ತಿ"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"ನಿರ್ವಾಹಕರ ಮೂಲಕ ನಿಯಂತ್ರಿಸಲಾಗಿದೆ"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"ನಿರ್ವಾಹಕರು ಸಕ್ರಿಯಗೊಳಿಸಿದ್ದಾರೆ"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"ನಿರ್ವಾಹಕರು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿದ್ದಾರೆ"</string>
     <string name="disabled" msgid="9206776641295849915">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"ಅನುಮತಿಸಲಾಗಿದೆ"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"ಅನುಮತಿಸಲಾಗುವುದಿಲ್ಲ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index d29bd65..b47471b 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"전원이 연결되었지만 현재 충전할 수 없음"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"충전 완료"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"관리자가 제어"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"관리자가 사용 설정함"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"관리자가 사용 중지함"</string>
     <string name="disabled" msgid="9206776641295849915">"사용 안함"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"허용됨"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"허용되지 않음"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 56b5da1..9853dac 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Сайылып турат, учурда кубаттоо мүмкүн эмес"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Толук"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Администратор тарабынан көзөмөлдөнөт"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Администратор иштетип койгон"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Администратор өчүрүп койгон"</string>
     <string name="disabled" msgid="9206776641295849915">"Өчүрүлгөн"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Уруксат берилген"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Тыюу салынган"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index eb27f02..1816515 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"ສຽບສາຍແລ້ວ, ບໍ່ສາມາດສາກໄດ້ໃນຕອນນີ້"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"ເຕັມ"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"ຄວບຄຸມໂດຍຜູ້ເບິ່ງແຍງ"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"ຜູ້ເບິ່ງແຍງລະບົບເປີດໃຫ້ໃຊ້ແລ້ວ"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"ຖືກຜູ້ເບິ່ງແຍງລະບົບປິດໄວ້"</string>
     <string name="disabled" msgid="9206776641295849915">"ປິດການນຳໃຊ້"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"ອະນຸຍາດແລ້ວ"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"ບໍ່ອະນຸຍາດແລ້ວ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 44b532b..e6a8e1c 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Įjungta į maitinimo lizdą, bet šiuo metu įkrauti neįmanoma"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Visiškai įkrautas"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Valdo administratorius"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Įgalino administratorius"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Išjungė administratorius"</string>
     <string name="disabled" msgid="9206776641295849915">"Neleidžiama"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Leidžiama"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Neleidžiama"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index ba87d07..b55afc0 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Pievienots, taču pašlaik nevar veikt uzlādi"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Pilns"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrolē administrators"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Iespējoja administrators"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Atspējoja administrators"</string>
     <string name="disabled" msgid="9206776641295849915">"Atspējots"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Atļauts"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Nav atļauts"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 0c5c94a..e28c8ee 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Приклучен е, но батеријата не може да се полни во моментов"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Полна"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Контролирано од администраторот"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Овозможено од администраторот"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Оневозможено од администраторот"</string>
     <string name="disabled" msgid="9206776641295849915">"Оневозможено"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Дозволено"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Не е дозволено"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 1a208e62..6860398 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"പ്ലഗ് ഇൻ ചെയ്‌തു, ഇപ്പോൾ ചാർജ് ചെയ്യാനാവില്ല"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"നിറഞ്ഞു"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"അഡ്‌മിൻ നിയന്ത്രിക്കുന്നത്"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"അഡ്‌മിൻ പ്രവർത്തനക്ഷമമാക്കി"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"അഡ്‌മിൻ പ്രവർത്തനരഹിതമാക്കി"</string>
     <string name="disabled" msgid="9206776641295849915">"പ്രവർത്തനരഹിതമാക്കി"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"അനുവദനീയം"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"അനുവദിച്ചിട്ടില്ല"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 809e82e..ba6d601 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Залгаастай тул одоо цэнэглэх боломжгүй"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Дүүрэн"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Админ удирдсан"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Админ идэвхжүүлсэн"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Админ цуцалсан"</string>
     <string name="disabled" msgid="9206776641295849915">"Идэвхгүйжүүлсэн"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Зөвшөөрсөн"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Зөвшөөрөөгүй"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index dfa6d2f..a5d230a 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"प्लग इन केलेले आहे, आता चार्ज करू शकत नाही"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"पूर्ण"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"प्रशासकाने नियंत्रित केलेले"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"प्रशासकाने सक्षम केलेले"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"प्रशासकाने अक्षम केलेले"</string>
     <string name="disabled" msgid="9206776641295849915">"अक्षम"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"अनुमती आहे"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"अनुमती नाही"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index b4ed016..a7ac3ef 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Dipalamkan, tidak boleh mengecas sekarang"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Penuh"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Dikawal oleh pentadbir"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Didayakan oleh pentadbir"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Dilumpuhkan oleh pentadbir"</string>
     <string name="disabled" msgid="9206776641295849915">"Dilumpuhkan"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Dibenarkan"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Tidak dibenarkan"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index c1ffd28..6cdab67 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"ပလပ်ထိုးထားသောကြောင့် ယခုအားသွင်း၍ မရသေးပါ"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"အပြည့်"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"စီမံခန့်ခွဲသူမှ ထိန်းချုပ်ပါသည်"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"စီမံခန့်ခွဲသူက ဖွင့်ထားသည်"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"စီမံခန့်ခွဲသူက ပိတ်ထားသည်"</string>
     <string name="disabled" msgid="9206776641295849915">"ပိတ်ထားပြီး"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"ခွင့်ပြုထားသည်"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"ခွင့်မပြုပါ"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 5a8e01e..cf18477 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Laderen er koblet til – kan ikke lade akkurat nå"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Fullt"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrollert av administratoren"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Slått på av administratoren"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Avslått av administratoren"</string>
     <string name="disabled" msgid="9206776641295849915">"Slått av"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Tillatt"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Ikke tillatt"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 72a9abb..8aba0f8 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"प्लगइन गरिएको छ, अहिले नै चार्ज गर्न सकिँदैन"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"पूर्ण चार्ज भएको स्थिति"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"प्रशासकद्वारा नियन्त्रित"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"प्रशासकद्वारा सक्षम पारिएको छ"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"प्रशासकद्वारा असक्षम पारिएको छ"</string>
     <string name="disabled" msgid="9206776641295849915">"असक्षम पारियो"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"अनुमति छ"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"अनुमति छैन"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index f341717..e3f1aea 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Aangesloten, kan nu niet opladen"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Volledig"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Ingesteld door beheerder"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Ingeschakeld door beheerder"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Uitgeschakeld door beheerder"</string>
     <string name="disabled" msgid="9206776641295849915">"Uitgeschakeld"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Toegestaan"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Niet toegestaan"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index a7761e9..8ecac4d 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"ପ୍ଲଗ୍‌ରେ ଲାଗିଛି, ହେଲେ ଏବେ ଚାର୍ଜ କରିପାରିବ ନାହିଁ"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"ଚାର୍ଜ ଅଛି"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"ଆଡ୍‌ମିନ୍‌ ଦ୍ୱାରା ନିୟନ୍ତ୍ରିତ"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"ଆଡମିନ୍‌ଙ୍କ ଦ୍ୱାରା ସକ୍ଷମ କରାଯାଇଛି"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"ଆଡ୍‌ମିନ୍‌ ଦ୍ଵାରା ଅକ୍ଷମ କରାଯାଇଛି"</string>
     <string name="disabled" msgid="9206776641295849915">"ଅକ୍ଷମ ହୋଇଛି"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"ଅନୁମୋଦିତ"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"ଅନୁମତି ନାହିଁ"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index c7ab379..6f17e13 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"ਪਲੱਗ ਲੱਗਾ ਹੋਇਆ ਹੈ, ਇਸ ਸਮੇਂ ਚਾਰਜ ਨਹੀਂ ਹੋ ਸਕਦੀ"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"ਪੂਰੀ"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਕੰਟਰੋਲ ਕੀਤੀ ਗਈ"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"ਪ੍ਰਸ਼ਾਸਕ ਦੁਆਰਾ ਯੋਗ ਬਣਾਇਆ ਗਿਆ"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"ਪ੍ਰਸ਼ਾਸਕ ਦੁਆਰਾ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ"</string>
     <string name="disabled" msgid="9206776641295849915">"ਅਯੋਗ ਬਣਾਇਆ"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"ਇਜਾਜ਼ਤ ਹੈ"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"ਇਜਾਜ਼ਤ ਨਹੀਂ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index effa59a..3c208e3 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Podłączony. Nie można teraz ładować"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Naładowana"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrolowane przez administratora"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Włączone przez administratora"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Wyłączone przez administratora"</string>
     <string name="disabled" msgid="9206776641295849915">"Wyłączone"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Dozwolone"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Niedozwolone"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index afefeda..5c363a4 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Conectado. Não é possível carregar no momento"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Carregada"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlada pelo admin"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Ativado pelo administrador"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Desativada pelo administrador"</string>
     <string name="disabled" msgid="9206776641295849915">"Desativado"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Permitido"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Não permitido"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 4ee4521..66c59ac 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Ligada à corrente, não é possível carregar neste momento"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Completo"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlado pelo gestor"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Ativada pelo gestor"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Desativada pelo gestor"</string>
     <string name="disabled" msgid="9206776641295849915">"Desativada"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Autorizada"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Não autorizada"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index afefeda..5c363a4 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Conectado. Não é possível carregar no momento"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Carregada"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlada pelo admin"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Ativado pelo administrador"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Desativada pelo administrador"</string>
     <string name="disabled" msgid="9206776641295849915">"Desativado"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Permitido"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Não permitido"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index f42363e..703add6 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Conectat, nu se poate încărca chiar acum"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Complet"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlată de administrator"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Activat de administrator"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Dezactivat de administrator"</string>
     <string name="disabled" msgid="9206776641295849915">"Dezactivată"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Permise"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Nepermise"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 451c710..4eb3ca4 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Подключено, не заряжается"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Батарея заряжена"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Контролируется администратором"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Включено администратором"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Отключено администратором"</string>
     <string name="disabled" msgid="9206776641295849915">"Отключено"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Разрешено"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Запрещено"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index d9e69ce..1ab5b79 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"පේනුගත කර ඇත, මේ අවස්ථාවේදී ආරෝපණය කළ නොහැකිය"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"පූර්ණ"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"පරිපාලක විසින් පාලනය කරන ලදී"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"පරිපාලක විසින් සබල කර ඇත"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"ඔබගේ පරිපාලක විසින් අබල කර ඇත"</string>
     <string name="disabled" msgid="9206776641295849915">"අබල කර ඇත"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"ඉඩ දුන්"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"ඉඩ නොදෙන"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index a0c1062..5c3920f 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Pripojené, ale nie je možné nabíjať"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Nabitá"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Ovládané správcom"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Povolené správcom"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Zakázané správcom"</string>
     <string name="disabled" msgid="9206776641295849915">"Deaktivované"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Povolené"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Nie je povolené"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 3088d0f..f479405 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Priključeno, trenutno ni mogoče polniti"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Poln"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Nadzira skrbnik"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Omogočil skrbnik"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Onemogočil skrbnik"</string>
     <string name="disabled" msgid="9206776641295849915">"Onemogočeno"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Dovoljene"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Ni dovoljeno"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 8e31013..2741985 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Në prizë, por nuk mund të ngarkohet për momentin"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"E mbushur"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrolluar nga administratori"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Aktivizuar nga administratori"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Çaktivizuar nga administratori"</string>
     <string name="disabled" msgid="9206776641295849915">"Çaktivizuar"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Lejohet"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Nuk lejohet"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index fe97119..241d9cb 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Прикључено је, али пуњење тренутно није могуће"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Пуна"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Контролише администратор"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Омогућио је администратор"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Администратор је онемогућио"</string>
     <string name="disabled" msgid="9206776641295849915">"Онемогућено"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Дозвољено"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Није дозвољено"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 11f446c..d338e96 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Inkopplad, kan inte laddas just nu"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Fullt"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Strys av administratören"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Aktiverad av administratör"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Inaktiverad av administratören"</string>
     <string name="disabled" msgid="9206776641295849915">"Inaktiverad"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Tillåts"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Tillåts inte"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index ba3aaba..df122e2 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Haiwezi kuchaji kwa sasa"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Imejaa"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Imedhibitiwa na msimamizi"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Imewashwa na msimamizi"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Imezimwa na msimamizi"</string>
     <string name="disabled" msgid="9206776641295849915">"Imezimwa"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Imeruhusiwa"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Hairuhusiwi"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 63d5e75..8f5c7d8 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"செருகப்பட்டது, ஆனால் இப்போது சார்ஜ் செய்ய முடியவில்லை"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"முழுவதும் சார்ஜ் ஆனது"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"நிர்வாகி கட்டுப்படுத்துகிறார்"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"நிர்வாகி இயக்கியுள்ளார்"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"நிர்வாகி முடக்கியுள்ளார்"</string>
     <string name="disabled" msgid="9206776641295849915">"முடக்கப்பட்டது"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"அனுமதிக்கப்பட்டது"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"அனுமதிக்கப்படவில்லை"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 4af461d..5f7ab996 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"ప్లగ్ ఇన్ చేయబడింది, ప్రస్తుతం ఛార్జ్ చేయడం సాధ్యం కాదు"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"నిండింది"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"నిర్వాహకుని ద్వారా నియంత్రించబడింది"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"నిర్వాహకులు ప్రారంభించారు"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"నిర్వాహకులు నిలిపివేసారు"</string>
     <string name="disabled" msgid="9206776641295849915">"నిలిపివేయబడింది"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"అనుమతించినవి"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"అనుమతించబడలేదు"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 9cc5c73..020baf0 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"เสียบอยู่ ไม่สามารถชาร์จได้ในขณะนี้"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"เต็ม"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"ผู้ดูแลระบบเป็นผู้ควบคุม"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"เปิดใช้โดยผู้ดูแลระบบ"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"ปิดใช้โดยผู้ดูแลระบบ"</string>
     <string name="disabled" msgid="9206776641295849915">"ปิดอยู่"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"อนุญาต"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"ไม่อนุญาต"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 49abe42..2164ade 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Nakasaksak, hindi makapag-charge sa ngayon"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Puno"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Pinapamahalaan ng admin"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Na-enable ng admin"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Na-disable ng admin"</string>
     <string name="disabled" msgid="9206776641295849915">"Naka-disable"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Pinapayagan"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Hindi pinapayagan"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 23a96d9..532927c 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Prize takıldı, şu anda şarj olamıyor"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Dolu"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Yönetici tarafından denetleniyor"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Yönetici tarafından etkinleştirildi"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Yönetici devre dışı bıraktı"</string>
     <string name="disabled" msgid="9206776641295849915">"Devre dışı"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"İzin verildi"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"İzin verilmiyor"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index cea870a4..cf26d20 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Підключено. Не вдається зарядити"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Акумулятор заряджено"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Керується адміністратором"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Увімкнено адміністратором"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Вимкнено адміністратором"</string>
     <string name="disabled" msgid="9206776641295849915">"Вимкнено"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Дозволено"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Заборонено"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 0fb60d9..c158179 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"پلگ ان ہے، ابھی چارج نہیں کر سکتے"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"مکمل"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"کنٹرول کردہ بذریعہ منتظم"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"منتظم کی طرف سے فعال کردہ"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"منتظم کی طرف سے غیر فعال کردہ"</string>
     <string name="disabled" msgid="9206776641295849915">"غیر فعال"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"اجازت ہے"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"اجازت نہیں ہے"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 4690db3..ac8bffe 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Ulangan, lekin quvvat olmayapti"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"To‘la"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Administrator tomonidan boshqariladi"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Administrator tomonidan yoqilgan"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Administrator tomonidan o‘chirilgan"</string>
     <string name="disabled" msgid="9206776641295849915">"O‘chiq"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Ruxsat berilgan"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Ruxsat berilmagan"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 937b37d..78306da 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Đã cắm nhưng không thể sạc ngay"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Đầy"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Do quản trị viên kiểm soát"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Kích hoạt bởi quản trị viên"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Bị quản trị viên vô hiệu hóa"</string>
     <string name="disabled" msgid="9206776641295849915">"Đã tắt"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Được phép"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Không được phép"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 47753fd..4fb26100 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"已插入电源,但是现在无法充电"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"电量充足"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"由管理员控制"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"已被管理员启用"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"已被管理员停用"</string>
     <string name="disabled" msgid="9206776641295849915">"已停用"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"允许"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"不允许"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 4cbf5a6..c5a8f92 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"已插入電源插座,但目前無法充電"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"電量已滿"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"已由管理員停用"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"已由管理員啟用"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"已由管理員停用"</string>
     <string name="disabled" msgid="9206776641295849915">"已停用"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"允許"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"不允許"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index cecc6ac..0947ccec 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"已接上電源,但現在無法充電"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"電力充足"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"已由管理員停用"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"已由管理員啟用"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"已由管理員停用"</string>
     <string name="disabled" msgid="9206776641295849915">"已停用"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"允許"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"不允許"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 94c3abf..cd90d74 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -395,8 +395,6 @@
     <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Kuxhunyiwe, ayikwazi ukushaja khona manje"</string>
     <string name="battery_info_status_full" msgid="2824614753861462808">"Kugcwele"</string>
     <string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kulawulwa umqondisi"</string>
-    <string name="enabled_by_admin" msgid="5302986023578399263">"Kunikwe amandla umlawuli"</string>
-    <string name="disabled_by_admin" msgid="8505398946020816620">"Kukhutshazwe umlawuli"</string>
     <string name="disabled" msgid="9206776641295849915">"Akusebenzi"</string>
     <string name="external_source_trusted" msgid="2707996266575928037">"Kuvumelekile"</string>
     <string name="external_source_untrusted" msgid="2677442511837596726">"Akuvumelekile"</string>
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index 8094b02..a9c5061 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -36,7 +36,6 @@
     <dimen name="two_target_pref_medium_icon_size">32dp</dimen>
 
     <!-- Lock icon for preferences locked by admin -->
-    <dimen name="restricted_icon_size">16dp</dimen>
     <dimen name="restricted_icon_padding">4dp</dimen>
 
     <dimen name="wifi_preference_badge_padding">8dip</dimen>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index ea6844e..332ced6 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -965,11 +965,6 @@
     <!-- Summary for settings preference disabled by administrator [CHAR LIMIT=50] -->
     <string name="disabled_by_admin_summary_text">Controlled by admin</string>
 
-    <!-- Summary for switch preference to denote it is switched on [CHAR LIMIT=50] -->
-    <string name="enabled_by_admin">Enabled by admin</string>
-    <!-- Summary for switch preference to denote it is switched off [CHAR LIMIT=50] -->
-    <string name="disabled_by_admin">Disabled by admin</string>
-
     <!-- [CHAR LIMIT=25] Manage applications, text telling using an application is disabled. -->
     <string name="disabled">Disabled</string>
     <!-- Summary of app trusted to install apps [CHAR LIMIT=45] -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/CustomDialogPreference.java b/packages/SettingsLib/src/com/android/settingslib/CustomDialogPreference.java
index 3bade25..192a40c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/CustomDialogPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/CustomDialogPreference.java
@@ -26,6 +26,12 @@
 import androidx.preference.DialogPreference;
 import androidx.preference.PreferenceDialogFragment;
 
+/**
+ * Framework version is deprecated, use the compat version instead.
+ *
+ * @deprecated
+ */
+@Deprecated
 public class CustomDialogPreference extends DialogPreference {
 
     private CustomPreferenceDialogFragment mFragment;
diff --git a/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java b/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java
index dfaff61..3caa0bb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java
@@ -31,6 +31,12 @@
 import androidx.preference.EditTextPreference;
 import androidx.preference.EditTextPreferenceDialogFragment;
 
+/**
+ * Framework version is deprecated, use the compat version instead.
+ *
+ * @deprecated
+ */
+@Deprecated
 public class CustomEditTextPreference extends EditTextPreference {
 
     private CustomPreferenceDialogFragment mFragment;
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
index 0094c2c..c03ba9a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
@@ -29,6 +29,7 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
+import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -55,9 +56,15 @@
      * @return drawables for displaying with settings that are locked by a device admin.
      */
     public static Drawable getRestrictedPadlock(Context context) {
-        Drawable restrictedPadlock = context.getDrawable(R.drawable.ic_info);
+        Drawable restrictedPadlock = context.getDrawable(android.R.drawable.ic_info);
         final int iconSize = context.getResources().getDimensionPixelSize(
-                R.dimen.restricted_icon_size);
+                android.R.dimen.config_restricted_icon_size);
+
+        TypedArray ta = context.obtainStyledAttributes(new int[]{android.R.attr.colorAccent});
+        int colorAccent = ta.getColor(0, 0);
+        ta.recycle();
+        restrictedPadlock.setTint(colorAccent);
+
         restrictedPadlock.setBounds(0, 0, iconSize, iconSize);
         return restrictedPadlock;
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index a710410..58feef5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -102,7 +102,7 @@
                 BluetoothProfile.A2DP);
     }
 
-    public boolean isConnectable() {
+    public boolean accessProfileEnabled() {
         return true;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
index e13e566..988062d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
@@ -96,7 +96,7 @@
                 BluetoothProfile.A2DP_SINK);
     }
 
-    public boolean isConnectable() {
+    public boolean accessProfileEnabled() {
         return true;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index b9f7323..750a843 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -29,16 +29,15 @@
 import android.text.TextUtils;
 import android.util.Log;
 
-import androidx.annotation.VisibleForTesting;
-
 import com.android.settingslib.R;
 
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
 
+import androidx.annotation.VisibleForTesting;
+
 /**
  * CachedBluetoothDevice represents a remote Bluetooth device. It contains
  * attributes of the device (such as the address, name, RSSI, etc.) and
@@ -48,6 +47,10 @@
 public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
     private static final String TAG = "CachedBluetoothDevice";
 
+    // See mConnectAttempted
+    private static final long MAX_UUID_DELAY_FOR_AUTO_CONNECT = 5000;
+    private static final long MAX_HOGP_DELAY_FOR_AUTO_CONNECT = 30000;
+
     private final Context mContext;
     private final BluetoothAdapter mLocalAdapter;
     private final LocalBluetoothProfileManager mProfileManager;
@@ -55,7 +58,6 @@
     private long mHiSyncId;
     // Need this since there is no method for getting RSSI
     private short mRssi;
-    private HashMap<LocalBluetoothProfile, Integer> mProfileConnectionState;
 
     private final List<LocalBluetoothProfile> mProfiles =
             new ArrayList<LocalBluetoothProfile>();
@@ -78,17 +80,6 @@
 
     private final static String MESSAGE_REJECTION_COUNT_PREFS_NAME = "bluetooth_message_reject";
 
-    public long getHiSyncId() {
-        return mHiSyncId;
-    }
-
-    public void setHiSyncId(long id) {
-        if (BluetoothUtils.D) {
-            Log.d(TAG, "setHiSyncId: mDevice " + mDevice + ", id " + id);
-        }
-        mHiSyncId = id;
-    }
-
     /**
      * Last time a bt profile auto-connect was attempted.
      * If an ACTION_UUID intent comes in within
@@ -97,14 +88,21 @@
      */
     private long mConnectAttempted;
 
-    // See mConnectAttempted
-    private static final long MAX_UUID_DELAY_FOR_AUTO_CONNECT = 5000;
-    private static final long MAX_HOGP_DELAY_FOR_AUTO_CONNECT = 30000;
-
     // Active device state
     private boolean mIsActiveDeviceA2dp = false;
     private boolean mIsActiveDeviceHeadset = false;
     private boolean mIsActiveDeviceHearingAid = false;
+
+    CachedBluetoothDevice(Context context, LocalBluetoothProfileManager profileManager,
+            BluetoothDevice device) {
+        mContext = context;
+        mLocalAdapter = BluetoothAdapter.getDefaultAdapter();
+        mProfileManager = profileManager;
+        mDevice = device;
+        fillData();
+        mHiSyncId = BluetoothHearingAid.HI_SYNC_ID_INVALID;
+    }
+
     /**
      * Describes the current device and profile for logging.
      *
@@ -133,7 +131,6 @@
             }
             return;
         }
-        mProfileConnectionState.put(profile, newProfileState);
         if (newProfileState == BluetoothProfile.STATE_CONNECTED) {
             if (profile instanceof MapProfile) {
                 profile.setPreferred(mDevice, true);
@@ -161,18 +158,6 @@
         fetchActiveDevices();
     }
 
-    CachedBluetoothDevice(Context context,
-                          LocalBluetoothProfileManager profileManager,
-                          BluetoothDevice device) {
-        mContext = context;
-        mLocalAdapter = BluetoothAdapter.getDefaultAdapter();
-        mProfileManager = profileManager;
-        mDevice = device;
-        mProfileConnectionState = new HashMap<LocalBluetoothProfile, Integer>();
-        fillData();
-        mHiSyncId = BluetoothHearingAid.HI_SYNC_ID_INVALID;
-    }
-
     public void disconnect() {
         for (LocalBluetoothProfile profile : mProfiles) {
             disconnect(profile);
@@ -204,6 +189,17 @@
         connectWithoutResettingTimer(connectAllProfiles);
     }
 
+    public long getHiSyncId() {
+        return mHiSyncId;
+    }
+
+    public void setHiSyncId(long id) {
+        if (BluetoothUtils.D) {
+            Log.d(TAG, "setHiSyncId: mDevice " + mDevice + ", id " + id);
+        }
+        mHiSyncId = id;
+    }
+
     void onBondingDockConnect() {
         // Attempt to connect if UUIDs are available. Otherwise,
         // we will connect when the ACTION_UUID intent arrives.
@@ -226,7 +222,7 @@
 
         int preferredProfiles = 0;
         for (LocalBluetoothProfile profile : mProfiles) {
-            if (connectAllProfiles ? profile.isConnectable() : profile.isAutoConnectable()) {
+            if (connectAllProfiles ? profile.accessProfileEnabled() : profile.isAutoConnectable()) {
                 if (profile.isPreferred(mDevice)) {
                     ++preferredProfiles;
                     connectInt(profile);
@@ -300,14 +296,6 @@
         return true;
     }
 
-    /**
-     * Return true if user initiated pairing on this device. The message text is
-     * slightly different for local vs. remote initiated pairing dialogs.
-     */
-    boolean isUserInitiatedPairing() {
-        return mDevice.isBondingInitiatedLocally();
-    }
-
     public void unpair() {
         int state = getBondState();
 
@@ -332,22 +320,9 @@
     }
 
     public int getProfileConnectionState(LocalBluetoothProfile profile) {
-        if (mProfileConnectionState.get(profile) == null) {
-            // If cache is empty make the binder call to get the state
-            int state = profile.getConnectionStatus(mDevice);
-            mProfileConnectionState.put(profile, state);
-        }
-        return mProfileConnectionState.get(profile);
-    }
-
-    public void clearProfileConnectionState ()
-    {
-        if (BluetoothUtils.D) {
-            Log.d(TAG," Clearing all connection state for dev:" + mDevice.getName());
-        }
-        for (LocalBluetoothProfile profile :getProfiles()) {
-            mProfileConnectionState.put(profile, BluetoothProfile.STATE_DISCONNECTED);
-        }
+        return profile != null
+                ? profile.getConnectionStatus(mDevice)
+                : BluetoothProfile.STATE_DISCONNECTED;
     }
 
     // TODO: do any of these need to run async on a background thread?
@@ -669,7 +644,7 @@
         List<LocalBluetoothProfile> connectableProfiles =
                 new ArrayList<LocalBluetoothProfile>();
         for (LocalBluetoothProfile profile : mProfiles) {
-            if (profile.isConnectable()) {
+            if (profile.accessProfileEnabled()) {
                 connectableProfiles.add(profile);
             }
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index e8f47e1..21cf0c2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -211,6 +211,26 @@
         }
     }
 
+    /**
+     * Attempts to get the name of a remote device, otherwise returns the address.
+     *
+     * @param device The remote device.
+     * @return The name, or if unavailable, the address.
+     */
+    public String getName(BluetoothDevice device) {
+        CachedBluetoothDevice cachedDevice = findDevice(device);
+        if (cachedDevice != null && cachedDevice.getName() != null) {
+            return cachedDevice.getName();
+        }
+
+        String name = device.getAliasName();
+        if (name != null) {
+            return name;
+        }
+
+        return device.getAddress();
+    }
+
     public synchronized void clearNonBondedDevices() {
 
         mCachedDevicesMapForHearingAids.entrySet().removeIf(entries
@@ -265,11 +285,6 @@
                     {
                         mCachedDevicesMapForHearingAids.remove(cachedDevice.getHiSyncId());
                     }
-                } else {
-                    // For bonded devices, we need to clear the connection status so that
-                    // when BT is enabled next time, device connection status shall be retrieved
-                    // by making a binder call.
-                    cachedDevice.clearProfileConnectionState();
                 }
             }
             for (int i = mHearingAidDevicesNotAddedInCache.size() - 1; i >= 0; i--) {
@@ -277,11 +292,6 @@
                 if (notCachedDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
                     notCachedDevice.setJustDiscovered(false);
                     mHearingAidDevicesNotAddedInCache.remove(i);
-                } else {
-                    // For bonded devices, we need to clear the connection status so that
-                    // when BT is enabled next time, device connection status shall be retrieved
-                    // by making a binder call.
-                    notCachedDevice.clearProfileConnectionState();
                 }
             }
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
index 2dd8eaf..62507f5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
@@ -103,7 +103,7 @@
                 BluetoothProfile.HEADSET);
     }
 
-    public boolean isConnectable() {
+    public boolean accessProfileEnabled() {
         return true;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
index 1eeb4f0..8bc0acf 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
@@ -100,7 +100,7 @@
                 new HearingAidServiceListener(), BluetoothProfile.HEARING_AID);
     }
 
-    public boolean isConnectable() {
+    public boolean accessProfileEnabled() {
         return false;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
index 4b6a22c..4879144 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
@@ -104,7 +104,7 @@
     }
 
     @Override
-    public boolean isConnectable() {
+    public boolean accessProfileEnabled() {
         return true;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
index 8c4bff5..61e5b6b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
@@ -29,7 +29,7 @@
 import java.util.List;
 
 /**
- * HidProfile handles Bluetooth HID profile.
+ * HidDeviceProfile handles Bluetooth HID Device role
  */
 public class HidDeviceProfile implements LocalBluetoothProfile {
     private static final String TAG = "HidDeviceProfile";
@@ -37,7 +37,6 @@
     private static final int ORDINAL = 18;
     // HID Device Profile is always preferred.
     private static final int PREFERRED_VALUE = -1;
-    private static final boolean DEBUG = true;
 
     private final CachedBluetoothDeviceManager mDeviceManager;
     private final LocalBluetoothProfileManager mProfileManager;
@@ -59,9 +58,7 @@
             implements BluetoothProfile.ServiceListener {
 
         public void onServiceConnected(int profile, BluetoothProfile proxy) {
-            if (DEBUG) {
-                Log.d(TAG,"Bluetooth service connected :-)");
-            }
+            Log.d(TAG, "Bluetooth service connected :-), profile:" + profile);
             mService = (BluetoothHidDevice) proxy;
             // We just bound to the service, so refresh the UI for any connected HID devices.
             List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -81,9 +78,7 @@
         }
 
         public void onServiceDisconnected(int profile) {
-            if (DEBUG) {
-                Log.d(TAG, "Bluetooth service disconnected");
-            }
+            Log.d(TAG, "Bluetooth service disconnected, profile:" + profile);
             mIsProfileReady = false;
         }
     }
@@ -99,7 +94,7 @@
     }
 
     @Override
-    public boolean isConnectable() {
+    public boolean accessProfileEnabled() {
         return true;
     }
 
@@ -110,6 +105,7 @@
 
     @Override
     public boolean connect(BluetoothDevice device) {
+        // Don't invoke method in service because settings is not allowed to connect this profile.
         return false;
     }
 
@@ -126,11 +122,7 @@
         if (mService == null) {
             return BluetoothProfile.STATE_DISCONNECTED;
         }
-        List<BluetoothDevice> deviceList = mService.getConnectedDevices();
-
-        return !deviceList.isEmpty() && deviceList.contains(device)
-                ? mService.getConnectionState(device)
-                : BluetoothProfile.STATE_DISCONNECTED;
+        return mService.getConnectionState(device);
     }
 
     @Override
@@ -185,9 +177,7 @@
     }
 
     protected void finalize() {
-        if (DEBUG) {
-            Log.d(TAG, "finalize()");
-        }
+        Log.d(TAG, "finalize()");
         if (mService != null) {
             try {
                 BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.HID_DEVICE,
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
index fe6b222..75d16db 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
@@ -93,7 +93,7 @@
                 BluetoothProfile.HID_HOST);
     }
 
-    public boolean isConnectable() {
+    public boolean accessProfileEnabled() {
         return true;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
index 0447f37..4b0ca74 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
@@ -26,9 +26,9 @@
 public interface LocalBluetoothProfile {
 
     /**
-     * Returns true if the user can initiate a connection, false otherwise.
+     * Return {@code true} if the user can initiate a connection for this profile in UI.
      */
-    boolean isConnectable();
+    boolean accessProfileEnabled();
 
     /**
      * Returns true if the user can enable auto connection for this profile.
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 7000f9d..0c29f43 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -290,10 +290,11 @@
                 }
             }
 
-            mEventManager.dispatchProfileConnectionStateChanged(cachedDevice, newState,
-                    mProfile.getProfileId());
             cachedDevice.onProfileStateChanged(mProfile, newState);
             cachedDevice.refresh();
+            // Dispatch profile changed after device update
+            mEventManager.dispatchProfileConnectionStateChanged(cachedDevice, newState,
+                    mProfile.getProfileId());
         }
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
index 7d334eb..1e22f44 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
@@ -32,11 +32,10 @@
 import java.util.List;
 
 /**
- * MapClientProfile handles Bluetooth MAP profile.
+ * MapClientProfile handles the Bluetooth MAP MCE role.
  */
 public final class MapClientProfile implements LocalBluetoothProfile {
     private static final String TAG = "MapClientProfile";
-    private static boolean V = false;
 
     private BluetoothMapClient mService;
     private boolean mIsProfileReady;
@@ -60,7 +59,7 @@
             implements BluetoothProfile.ServiceListener {
 
         public void onServiceConnected(int profile, BluetoothProfile proxy) {
-            if (V) Log.d(TAG,"Bluetooth service connected");
+            Log.d(TAG, "Bluetooth service connected, profile:" + profile);
             mService = (BluetoothMapClient) proxy;
             // We just bound to the service, so refresh the UI for any connected MAP devices.
             List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -82,14 +81,14 @@
         }
 
         public void onServiceDisconnected(int profile) {
-            if (V) Log.d(TAG,"Bluetooth service disconnected");
+            Log.d(TAG, "Bluetooth service disconnected, profile:" + profile);
             mProfileManager.callServiceDisconnectedListeners();
             mIsProfileReady=false;
         }
     }
 
     public boolean isProfileReady() {
-        if(V) Log.d(TAG,"isProfileReady(): "+ mIsProfileReady);
+        Log.d(TAG, "isProfileReady(): "+ mIsProfileReady);
         return mIsProfileReady;
     }
 
@@ -106,7 +105,7 @@
                 new MapClientServiceListener(), BluetoothProfile.MAP_CLIENT);
     }
 
-    public boolean isConnectable() {
+    public boolean accessProfileEnabled() {
         return true;
     }
 
@@ -115,18 +114,16 @@
     }
 
     public boolean connect(BluetoothDevice device) {
-        if (mService == null) return false;
-        List<BluetoothDevice> connectedDevices = getConnectedDevices();
-        if (connectedDevices != null && connectedDevices.contains(device)) {
-            // Connect to same device, Ignore it
-            Log.d(TAG,"Ignoring Connect");
-            return true;
+        if (mService == null) {
+            return false;
         }
         return mService.connect(device);
     }
 
     public boolean disconnect(BluetoothDevice device) {
-        if (mService == null) return false;
+        if (mService == null) {
+            return false;
+        }
         // Downgrade priority as user is disconnecting.
         if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
             mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
@@ -135,23 +132,30 @@
     }
 
     public int getConnectionStatus(BluetoothDevice device) {
-        if (mService == null) return BluetoothProfile.STATE_DISCONNECTED;
-
+        if (mService == null) {
+            return BluetoothProfile.STATE_DISCONNECTED;
+        }
         return mService.getConnectionState(device);
     }
 
     public boolean isPreferred(BluetoothDevice device) {
-        if (mService == null) return false;
+        if (mService == null) {
+            return false;
+        }
         return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
     }
 
     public int getPreferred(BluetoothDevice device) {
-        if (mService == null) return BluetoothProfile.PRIORITY_OFF;
+        if (mService == null) {
+            return BluetoothProfile.PRIORITY_OFF;
+        }
         return mService.getPriority(device);
     }
 
     public void setPreferred(BluetoothDevice device, boolean preferred) {
-        if (mService == null) return;
+        if (mService == null) {
+            return;
+        }
         if (preferred) {
             if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
                 mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
@@ -162,7 +166,9 @@
     }
 
     public List<BluetoothDevice> getConnectedDevices() {
-        if (mService == null) return new ArrayList<BluetoothDevice>(0);
+        if (mService == null) {
+            return new ArrayList<BluetoothDevice>(0);
+        }
         return mService.getDevicesMatchingConnectionStates(
               new int[] {BluetoothProfile.STATE_CONNECTED,
                          BluetoothProfile.STATE_CONNECTING,
@@ -200,11 +206,11 @@
     }
 
     protected void finalize() {
-        if (V) Log.d(TAG, "finalize()");
+        Log.d(TAG, "finalize()");
         if (mService != null) {
             try {
                 BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.MAP_CLIENT,
-                                                                       mService);
+                        mService);
                 mService = null;
             }catch (Throwable t) {
                 Log.w(TAG, "Error cleaning up MAP Client proxy", t);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
index caea04f..7582024 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
@@ -104,7 +104,7 @@
                 BluetoothProfile.MAP);
     }
 
-    public boolean isConnectable() {
+    public boolean accessProfileEnabled() {
         return true;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
index dfd1622..e1e5dbe 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
@@ -32,7 +32,7 @@
     // Order of this profile in device profiles list
     private static final int ORDINAL = 2;
 
-    public boolean isConnectable() {
+    public boolean accessProfileEnabled() {
         return false;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
index 02afe8d..7b81162 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
@@ -78,7 +78,7 @@
             BluetoothProfile.PAN);
     }
 
-    public boolean isConnectable() {
+    public boolean accessProfileEnabled() {
         return true;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
index b295f24..1f15601 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
@@ -34,7 +34,6 @@
 
 public final class PbapClientProfile implements LocalBluetoothProfile {
     private static final String TAG = "PbapClientProfile";
-    private static boolean V = false;
 
     private BluetoothPbapClient mService;
     private boolean mIsProfileReady;
@@ -56,9 +55,7 @@
             implements BluetoothProfile.ServiceListener {
 
         public void onServiceConnected(int profile, BluetoothProfile proxy) {
-            if (V) {
-                Log.d(TAG,"Bluetooth service connected");
-            }
+            Log.d(TAG, "Bluetooth service connected, profile:" + profile);
             mService = (BluetoothPbapClient) proxy;
             // We just bound to the service, so refresh the UI for any connected PBAP devices.
             List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -77,9 +74,7 @@
         }
 
         public void onServiceDisconnected(int profile) {
-            if (V) {
-                Log.d(TAG,"Bluetooth service disconnected");
-            }
+            Log.d(TAG, "Bluetooth service disconnected, profile:" + profile);
             mIsProfileReady = false;
         }
     }
@@ -112,7 +107,7 @@
                 new PbapClientServiceListener(), BluetoothProfile.PBAP_CLIENT);
     }
 
-    public boolean isConnectable() {
+    public boolean accessProfileEnabled() {
         return true;
     }
 
@@ -131,31 +126,16 @@
     }
 
     public boolean connect(BluetoothDevice device) {
-        if (V) {
-            Log.d(TAG,"PBAPClientProfile got connect request");
-        }
+        Log.d(TAG,"PBAPClientProfile got connect request");
         if (mService == null) {
             return false;
         }
-        List<BluetoothDevice> srcs = getConnectedDevices();
-        if (srcs != null) {
-            for (BluetoothDevice src : srcs) {
-                if (src.equals(device)) {
-                    // Connect to same device, Ignore it
-                    Log.d(TAG,"Ignoring Connect");
-                    return true;
-                }
-            }
-        }
         Log.d(TAG,"PBAPClientProfile attempting to connect to " + device.getAddress());
-
         return mService.connect(device);
     }
 
     public boolean disconnect(BluetoothDevice device) {
-        if (V) {
-            Log.d(TAG,"PBAPClientProfile got disconnect request");
-        }
+        Log.d(TAG,"PBAPClientProfile got disconnect request");
         if (mService == null) {
             return false;
         }
@@ -218,9 +198,7 @@
     }
 
     protected void finalize() {
-        if (V) {
-            Log.d(TAG, "finalize()");
-        }
+        Log.d(TAG, "finalize()");
         if (mService != null) {
             try {
                 BluetoothAdapter.getDefaultAdapter().closeProfileProxy(
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
index e9d8cb5..adef0841 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
@@ -80,7 +80,7 @@
         BluetoothPbap pbap = new BluetoothPbap(context, new PbapServiceListener());
     }
 
-    public boolean isConnectable() {
+    public boolean accessProfileEnabled() {
         return true;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
index 61602c6..9a6f104 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
@@ -106,7 +106,7 @@
                 BluetoothProfile.SAP);
     }
 
-    public boolean isConnectable() {
+    public boolean accessProfileEnabled() {
         return true;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoader.java
index 223c055..60d22a0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoader.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoader.java
@@ -34,8 +34,11 @@
 import com.android.settingslib.AppItem;
 
 /**
- * Loader for historical chart data for both network and UID details.
+ * Framework loader is deprecated, use the compat version instead.
+ *
+ * @deprecated
  */
+@Deprecated
 public class ChartDataLoader extends AsyncTaskLoader<ChartData> {
     private static final String KEY_TEMPLATE = "template";
     private static final String KEY_APP = "app";
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoaderCompat.java b/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoaderCompat.java
index c3241bb..74bd97f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoaderCompat.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoaderCompat.java
@@ -36,7 +36,12 @@
 
 /**
  * Loader for historical chart data for both network and UID details.
+ *
+ * Deprecated in favor of {@link NetworkCycleDataLoader}
+ *
+ * @deprecated
  */
+@Deprecated
 public class ChartDataLoaderCompat extends AsyncTaskLoader<ChartData> {
     private static final String KEY_TEMPLATE = "template";
     private static final String KEY_APP = "app";
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleData.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleData.java
new file mode 100644
index 0000000..2d8c0de
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleData.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.net;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Data structure representing usage data in a billing cycle.
+ */
+public class NetworkCycleData {
+    public static final long BUCKET_DURATION_MS = TimeUnit.DAYS.toMillis(1);
+    public long startTime;
+    public long endTime;
+    public long totalUsage;
+    public List<NetworkCycleData> usageBuckets;
+
+    private NetworkCycleData(Builder builder) {
+        startTime = builder.mStart;
+        endTime = builder.mEnd;
+        totalUsage = builder.mTotalUsage;
+        usageBuckets = builder.mUsageBuckets;
+    }
+
+    public static class Builder {
+        private long mStart;
+        private long mEnd;
+        private long mTotalUsage;
+        private List<NetworkCycleData> mUsageBuckets;
+
+        public Builder setStartTime(long start) {
+            mStart = start;
+            return this;
+        }
+
+        public Builder setEndTime(long end) {
+            mEnd = end;
+            return this;
+        }
+
+        public Builder setTotalUsage(long total) {
+            mTotalUsage = total;
+            return this;
+        }
+
+        public Builder setUsageBuckets(List<NetworkCycleData> buckets) {
+            mUsageBuckets = buckets;
+            return this;
+        }
+
+        public NetworkCycleData build() {
+            return new NetworkCycleData(this);
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataLoader.java
new file mode 100644
index 0000000..80e1356
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataLoader.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.net;
+
+import static android.net.NetworkStatsHistory.FIELD_RX_BYTES;
+import static android.net.NetworkStatsHistory.FIELD_TX_BYTES;
+
+import android.app.usage.NetworkStats;
+import android.app.usage.NetworkStatsManager;
+import android.content.Context;
+import android.net.INetworkStatsService;
+import android.net.INetworkStatsSession;
+import android.net.NetworkPolicy;
+import android.net.NetworkPolicyManager;
+import android.net.NetworkStatsHistory;
+import android.net.NetworkTemplate;
+import android.net.TrafficStats;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.text.format.DateUtils;
+import android.util.Log;
+import android.util.Pair;
+
+import java.time.ZonedDateTime;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+import androidx.loader.content.AsyncTaskLoader;
+
+/**
+ * Loader for network data usage history. It returns a list of usage data per billing cycle.
+ */
+public class NetworkCycleDataLoader extends AsyncTaskLoader<List<NetworkCycleData>> {
+    private static final String TAG = "CycleDataSummaryLoader";
+    private final NetworkStatsManager mNetworkStatsManager;
+    private final String mSubId;
+    private final int mNetworkType;
+    private final NetworkPolicy mPolicy;
+    private final NetworkTemplate mNetworkTemplate;
+    @VisibleForTesting
+    final INetworkStatsService mNetworkStatsService;
+
+    private NetworkCycleDataLoader(Builder builder) {
+        super(builder.mContext);
+        mPolicy = builder.mPolicy;
+        mSubId = builder.mSubId;
+        mNetworkType = builder.mNetworkType;
+        mNetworkTemplate = builder.mNetworkTemplate;
+        mNetworkStatsManager = (NetworkStatsManager)
+            builder.mContext.getSystemService(Context.NETWORK_STATS_SERVICE);
+        mNetworkStatsService = INetworkStatsService.Stub.asInterface(
+            ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
+    }
+
+    @Override
+    protected void onStartLoading() {
+        super.onStartLoading();
+        forceLoad();
+    }
+
+    @Override
+    public List<NetworkCycleData> loadInBackground() {
+        if (mPolicy == null) {
+            return loadFourWeeksData();
+        }
+        final List<NetworkCycleData> data = new ArrayList<>();
+        final Iterator<Pair<ZonedDateTime, ZonedDateTime>> iterator = NetworkPolicyManager
+            .cycleIterator(mPolicy);
+        while (iterator.hasNext()) {
+            final Pair<ZonedDateTime, ZonedDateTime> cycle = iterator.next();
+            final long cycleStart = cycle.first.toInstant().toEpochMilli();
+            final long cycleEnd = cycle.second.toInstant().toEpochMilli();
+            getUsage(cycleStart, cycleEnd, data);
+        }
+        return data;
+    }
+
+    @Override
+    protected void onStopLoading() {
+        super.onStopLoading();
+        cancelLoad();
+    }
+
+    @Override
+    protected void onReset() {
+        super.onReset();
+        cancelLoad();
+    }
+
+    @VisibleForTesting
+    List<NetworkCycleData> loadFourWeeksData() {
+        final List<NetworkCycleData> data = new ArrayList<>();
+        try {
+            final INetworkStatsSession networkSession = mNetworkStatsService.openSession();
+            final NetworkStatsHistory networkHistory = networkSession.getHistoryForNetwork(
+                mNetworkTemplate, FIELD_RX_BYTES | FIELD_TX_BYTES);
+            final long historyStart = networkHistory.getStart();
+            final long historyEnd = networkHistory.getEnd();
+
+            long cycleEnd = historyEnd;
+            while (cycleEnd > historyStart) {
+                final long cycleStart = cycleEnd - (DateUtils.WEEK_IN_MILLIS * 4);
+                getUsage(cycleStart, cycleEnd, data);
+                cycleEnd = cycleStart;
+            }
+
+            TrafficStats.closeQuietly(networkSession);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+        return data;
+    }
+
+    @VisibleForTesting
+    void getUsage(long start, long end, @NonNull List<NetworkCycleData> data) {
+        try {
+            final NetworkStats stats = mNetworkStatsManager.querySummary(
+                mNetworkType, mSubId, start, end);
+            final long total = getTotalUsage(stats);
+            if (total > 0L) {
+                data.add(new NetworkCycleData.Builder()
+                    .setStartTime(start)
+                    .setEndTime(end)
+                    .setTotalUsage(total)
+                    .setUsageBuckets(getUsageBuckets(start, end))
+                    .build());
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Exception querying network detail.", e);
+        }
+    }
+
+    private long getTotalUsage(NetworkStats stats) {
+        long bytes = 0L;
+        if (stats != null) {
+            final NetworkStats.Bucket bucket = new NetworkStats.Bucket();
+            while (stats.hasNextBucket() && stats.getNextBucket(bucket)) {
+                bytes += bucket.getRxBytes() + bucket.getTxBytes();
+            }
+            stats.close();
+        }
+        return bytes;
+    }
+
+    private List<NetworkCycleData> getUsageBuckets(long start, long end) {
+        final List<NetworkCycleData> data = new ArrayList<>();
+        long bucketStart = start;
+        long bucketEnd = start + NetworkCycleData.BUCKET_DURATION_MS;
+        while (bucketEnd <= end) {
+            long usage = 0L;
+            try {
+                final NetworkStats stats = mNetworkStatsManager.querySummary(
+                    mNetworkType, mSubId, bucketStart, bucketEnd);
+                usage = getTotalUsage(stats);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Exception querying network detail.", e);
+            }
+            data.add(new NetworkCycleData.Builder()
+                .setStartTime(bucketStart).setEndTime(bucketEnd).setTotalUsage(usage).build());
+            bucketStart = bucketEnd;
+            bucketEnd += NetworkCycleData.BUCKET_DURATION_MS;
+        }
+        return data;
+    }
+
+    public static class Builder {
+        private final Context mContext;
+        private NetworkPolicy mPolicy;
+        private String mSubId;
+        private int mNetworkType;
+        private NetworkTemplate mNetworkTemplate;
+
+        public Builder(Context context) {
+            mContext = context;
+        }
+
+        public Builder setNetworkPolicy(NetworkPolicy policy) {
+            mPolicy = policy;
+            return this;
+        }
+
+        public Builder setSubscriberId(String subId) {
+            mSubId = subId;
+            return this;
+        }
+
+        public Builder setNetworkType(int networkType) {
+            mNetworkType = networkType;
+            return this;
+        }
+
+        public Builder setNetworkTemplate(NetworkTemplate template) {
+            mNetworkTemplate = template;
+            return this;
+        }
+
+        public NetworkCycleDataLoader build() {
+            return new NetworkCycleDataLoader(this);
+        }
+    }
+
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsSummaryLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsSummaryLoader.java
new file mode 100644
index 0000000..34e6097
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsSummaryLoader.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.net;
+
+import android.app.usage.NetworkStatsManager;
+import android.app.usage.NetworkStats;
+import android.content.Context;
+import android.os.RemoteException;
+import android.util.Log;
+
+import androidx.loader.content.AsyncTaskLoader;
+
+/**
+ * Loader for retrieving the network stats summary for all UIDs.
+ */
+public class NetworkStatsSummaryLoader extends AsyncTaskLoader<NetworkStats> {
+
+    private static final String TAG = "NetworkDetailLoader";
+    private final NetworkStatsManager mNetworkStatsManager;
+    private final long mStart;
+    private final long mEnd;
+    private final String mSubId;
+    private final int mNetworkType;
+
+    private NetworkStatsSummaryLoader(Builder builder) {
+        super(builder.mContext);
+        mStart = builder.mStart;
+        mEnd = builder.mEnd;
+        mSubId = builder.mSubId;
+        mNetworkType = builder.mNetworkType;
+        mNetworkStatsManager = (NetworkStatsManager)
+                builder.mContext.getSystemService(Context.NETWORK_STATS_SERVICE);
+    }
+
+    @Override
+    protected void onStartLoading() {
+        super.onStartLoading();
+        forceLoad();
+    }
+
+    @Override
+    public NetworkStats loadInBackground() {
+        try {
+            return mNetworkStatsManager.querySummary(mNetworkType, mSubId, mStart, mEnd);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Exception querying network detail.", e);
+            return null;
+        }
+    }
+
+    @Override
+    protected void onStopLoading() {
+        super.onStopLoading();
+        cancelLoad();
+    }
+
+    @Override
+    protected void onReset() {
+        super.onReset();
+        cancelLoad();
+    }
+
+    public static class Builder {
+        private final Context mContext;
+        private long mStart;
+        private long mEnd;
+        private String mSubId;
+        private int mNetworkType;
+
+        public Builder(Context context) {
+            mContext = context;
+        }
+
+        public Builder setStartTime(long start) {
+            mStart = start;
+            return this;
+        }
+
+        public Builder setEndTime(long end) {
+            mEnd = end;
+            return this;
+        }
+
+        public Builder setSubscriberId(String subId) {
+            mSubId = subId;
+            return this;
+        }
+
+        public Builder setNetworkType(int networkType) {
+            mNetworkType = networkType;
+            return this;
+        }
+
+        public NetworkStatsSummaryLoader build() {
+            return new NetworkStatsSummaryLoader(this);
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoader.java
index 572bae1..649aeff 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoader.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoader.java
@@ -24,6 +24,12 @@
 import android.os.Bundle;
 import android.os.RemoteException;
 
+/**
+ * Framework loader is deprecated, use the compat version instead.
+ *
+ * @deprecated
+ */
+@Deprecated
 public class SummaryForAllUidLoader extends AsyncTaskLoader<NetworkStats> {
     private static final String KEY_TEMPLATE = "template";
     private static final String KEY_START = "start";
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoaderCompat.java b/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoaderCompat.java
index c311337..82bb011 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoaderCompat.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoaderCompat.java
@@ -25,6 +25,12 @@
 
 import androidx.loader.content.AsyncTaskLoader;
 
+/**
+ * Deprecated in favor of {@link NetworkStatsDetailLoader}
+ *
+ * @deprecated
+ */
+@Deprecated
 public class SummaryForAllUidLoaderCompat extends AsyncTaskLoader<NetworkStats> {
     private static final String KEY_TEMPLATE = "template";
     private static final String KEY_START = "start";
diff --git a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionControllerMixin.java b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionControllerMixin.java
index 6597daa..b0e987e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionControllerMixin.java
+++ b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionControllerMixin.java
@@ -32,8 +32,11 @@
 import java.util.List;
 
 /**
- * Manages IPC communication to SettingsIntelligence for suggestion related services.
+ * Framework mixin is deprecated, use the compat version instead.
+ *
+ * @deprecated
  */
+@Deprecated
 public class SuggestionControllerMixin implements SuggestionController.ServiceConnectionListener,
         androidx.lifecycle.LifecycleObserver, LoaderManager.LoaderCallbacks<List<Suggestion>> {
 
@@ -65,7 +68,7 @@
         mContext = context.getApplicationContext();
         mHost = host;
         mSuggestionController = new SuggestionController(mContext, componentName,
-                    this /* serviceConnectionListener */);
+                this /* serviceConnectionListener */);
         if (lifecycle != null) {
             lifecycle.addObserver(this);
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionLoader.java b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionLoader.java
index 9c1af1e..8011424 100644
--- a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionLoader.java
+++ b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionLoader.java
@@ -24,6 +24,12 @@
 
 import java.util.List;
 
+/**
+ * Framework loader is deprecated, use the compat version instead.
+ *
+ * @deprecated
+ */
+@Deprecated
 public class SuggestionLoader extends AsyncLoader<List<Suggestion>> {
 
     public static final int LOADER_ID_SUGGESTIONS = 42;
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/AsyncLoader.java b/packages/SettingsLib/src/com/android/settingslib/utils/AsyncLoader.java
index 06770ac..64b9ffe 100644
--- a/packages/SettingsLib/src/com/android/settingslib/utils/AsyncLoader.java
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/AsyncLoader.java
@@ -29,7 +29,9 @@
  * This loader is based on the MailAsyncTaskLoader from the AOSP EmailUnified repo.
  *
  * @param <T> the data type to be loaded.
+ * @deprecated Framework loader is deprecated, use the compat version instead.
  */
+@Deprecated
 public abstract class AsyncLoader<T> extends AsyncTaskLoader<T> {
     private T mResult;
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreferenceMixin.java b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreferenceMixin.java
index 2987c15..fcf2363 100644
--- a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreferenceMixin.java
+++ b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreferenceMixin.java
@@ -25,6 +25,12 @@
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
 import com.android.settingslib.core.lifecycle.events.SetPreferenceScreen;
 
+/**
+ * Framework mixin is deprecated, use the compat version instead.
+ *
+ * @deprecated
+ */
+@Deprecated
 public class FooterPreferenceMixin implements LifecycleObserver, SetPreferenceScreen {
 
     private final PreferenceFragment mFragment;
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 9050b4b..0dbc037 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -81,7 +81,7 @@
     private static final long DEFAULT_MAX_CACHED_SCORE_AGE_MILLIS = 20 * DateUtils.MINUTE_IN_MILLIS;
 
     /** Maximum age of scan results to hold onto while actively scanning. **/
-    private static final long MAX_SCAN_RESULT_AGE_MILLIS = 25000;
+    private static final long MAX_SCAN_RESULT_AGE_MILLIS = 15000;
 
     private static final String TAG = "WifiTracker";
     private static final boolean DBG() {
@@ -134,8 +134,8 @@
     /**
      * Tracks whether fresh scan results have been received since scanning start.
      *
-     * <p>If this variable is false, we will not evict the scan result cache or invoke callbacks
-     * so that we do not update the UI with stale data / clear out existing UI elements prematurely.
+     * <p>If this variable is false, we will not invoke callbacks so that we do not
+     * update the UI with stale data / clear out existing UI elements prematurely.
      */
     private boolean mStaleScanResults = true;
 
@@ -327,7 +327,8 @@
      * <p>Intended to only be invoked within {@link #onStart()}.
      */
     @MainThread
-    private void forceUpdate() {
+    @VisibleForTesting
+    void forceUpdate() {
         mLastInfo = mWifiManager.getConnectionInfo();
         mLastNetworkInfo = mConnectivityManager.getNetworkInfo(mWifiManager.getCurrentNetwork());
 
@@ -443,10 +444,8 @@
             mScanResultCache.put(newResult.BSSID, newResult);
         }
 
-        // Don't evict old results if no new scan results
-        if (!mStaleScanResults) {
-            evictOldScans();
-        }
+        // Evict old results in all conditions
+        evictOldScans();
 
         ArrayMap<String, List<ScanResult>> scanResultsByApKey = new ArrayMap<>();
         for (ScanResult result : mScanResultCache.values()) {
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index 517db78..1860b31 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -21,7 +21,6 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.doAnswer;
@@ -104,6 +103,10 @@
     private static final byte SCORE_2 = 15;
     private static final int BADGE_2 = AccessPoint.Speed.FAST;
 
+    private static final String SSID_3 = "ssid3";
+    private static final String BSSID_3 = "CC:00:00:00:00:00";
+    private static final int RSSI_3 = -40;
+
     // TODO(b/65594609): Convert mutable Data objects to instance variables / builder pattern
     private static final int NETWORK_ID_1 = 123;
     private static final int CONNECTED_RSSI = -50;
@@ -255,6 +258,19 @@
                 SystemClock.elapsedRealtime() * 1000 /* microsecond timestamp */);
     }
 
+    private static ScanResult buildStaleScanResult() {
+        return new ScanResult(
+                WifiSsid.createFromAsciiEncoded(SSID_3),
+                BSSID_3,
+                0, // hessid
+                0, //anqpDomainId
+                null, // osuProviders
+                "", // capabilities
+                RSSI_3,
+                0, // frequency
+                0 /* microsecond timestamp */);
+    }
+
     private WifiTracker createTrackerWithImmediateBroadcastsAndInjectInitialScanResults(
                     Intent ... intents)
             throws InterruptedException {
@@ -896,4 +912,18 @@
         assertThat(aps.get(0).isReachable()).isTrue();
         assertThat(aps.get(1).isReachable()).isTrue();
     }
+
+    @Test
+    public void onStart_updateScanResults_evictOldScanResult() {
+        when(mockWifiManager.getScanResults()).thenReturn(
+                Arrays.asList(buildScanResult1(), buildScanResult2(), buildStaleScanResult()));
+        WifiTracker tracker = createMockedWifiTracker();
+
+        tracker.forceUpdate();
+
+        // Only has scanResult1 and scanResult2
+        assertThat(tracker.getAccessPoints()).hasSize(2);
+        assertThat(tracker.getAccessPoints().get(0).getBssid()).isEqualTo(BSSID_1);
+        assertThat(tracker.getAccessPoints().get(1).getBssid()).isEqualTo(BSSID_2);
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java
index dde1746..ede248b 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java
@@ -52,6 +52,9 @@
                 @Override
                 public List<ResourcePath> getIncludedResourcePaths() {
                     final List<ResourcePath> paths = super.getIncludedResourcePaths();
+                    paths.add(resourcePath("file:frameworks/base/packages/SettingsLib/AppPreference/res"));
+                    paths.add(resourcePath("file:frameworks/base/packages/SettingsLib/HelpUtils/res"));
+                    paths.add(resourcePath("file:frameworks/base/packages/SettingsLib/RestrictedLockUtils/res"));
                     paths.add(resourcePath("file:frameworks/base/packages/SettingsLib/res"));
                     paths.add(resourcePath("file:frameworks/base/core/res/res"));
                     paths.add(resourcePath("file:out/soong/.intermediates/prebuilts/sdk/current/androidx/androidx.appcompat_appcompat-nodeps/android_common/aar/res/"));
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
index 8ac611f..62b5688 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
@@ -118,7 +118,7 @@
      * Test to verify addDevice().
      */
     @Test
-    public void testAddDevice_validCachedDevices_devicesAdded() {
+    public void addDevice_validCachedDevices_devicesAdded() {
         CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
         CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
@@ -136,17 +136,17 @@
      * Test to verify getName().
      */
     @Test
-    public void testGetName_validCachedDevice_nameFound() {
+    public void getName_validCachedDevice_nameFound() {
         CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
-        assertThat(mCachedDeviceManager.findDevice(mDevice1).getName()).isEqualTo(DEVICE_ALIAS_1);
+        assertThat(mCachedDeviceManager.getName(mDevice1)).isEqualTo(DEVICE_ALIAS_1);
     }
 
     /**
      * Test to verify onDeviceNameUpdated().
      */
     @Test
-    public void testOnDeviceNameUpdated_validName_nameUpdated() {
+    public void onDeviceNameUpdated_validName_nameUpdated() {
         CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
         assertThat(cachedDevice1.getName()).isEqualTo(DEVICE_ALIAS_1);
@@ -161,7 +161,7 @@
      * Test to verify clearNonBondedDevices().
      */
     @Test
-    public void testClearNonBondedDevices_bondedAndNonBondedDevices_nonBondedDevicesCleared() {
+    public void clearNonBondedDevices_bondedAndNonBondedDevices_nonBondedDevicesCleared() {
         CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
         CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
@@ -193,7 +193,7 @@
      * Test to verify clearNonBondedDevices() for hearing aids.
      */
     @Test
-    public void testClearNonBondedDevices_HearingAids_nonBondedHAsClearedFromCachedDevicesMap() {
+    public void clearNonBondedDevices_HearingAids_nonBondedHAsClearedFromCachedDevicesMap() {
         when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
         when(mDevice2.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
 
@@ -214,7 +214,7 @@
      * Test to verify onHiSyncIdChanged() for hearing aid devices with same HiSyncId.
      */
     @Test
-    public void testOnHiSyncIdChanged_sameHiSyncId_populateInDifferentLists() {
+    public void onHiSyncIdChanged_sameHiSyncId_populateInDifferentLists() {
         CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
         CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
@@ -247,7 +247,7 @@
      * device is connected and other is disconnected. The connected device should be chosen.
      */
     @Test
-    public void testOnHiSyncIdChanged_sameHiSyncIdAndOneConnected_chooseConnectedDevice() {
+    public void onHiSyncIdChanged_sameHiSyncIdAndOneConnected_chooseConnectedDevice() {
         CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
         CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
@@ -282,7 +282,7 @@
      * Test to verify onHiSyncIdChanged() for hearing aid devices with different HiSyncId.
      */
     @Test
-    public void testOnHiSyncIdChanged_differentHiSyncId_populateInSameList() {
+    public void onHiSyncIdChanged_differentHiSyncId_populateInSameList() {
         CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
         CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
@@ -316,7 +316,7 @@
      * Test to verify onProfileConnectionStateChanged() for single hearing aid device connection.
      */
     @Test
-    public void testOnProfileConnectionStateChanged_singleDeviceConnected_visible() {
+    public void onProfileConnectionStateChanged_singleDeviceConnected_visible() {
         CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
         cachedDevice1.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
@@ -353,7 +353,7 @@
      * devices are disconnected and they get connected.
      */
     @Test
-    public void testOnProfileConnectionStateChanged_twoDevicesConnected_oneDeviceVisible() {
+    public void onProfileConnectionStateChanged_twoDevicesConnected_oneDeviceVisible() {
         CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
         CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
@@ -405,7 +405,7 @@
      * devices are connected and they get disconnected.
      */
     @Test
-    public void testOnProfileConnectionStateChanged_twoDevicesDisconnected_oneDeviceVisible() {
+    public void onProfileConnectionStateChanged_twoDevicesDisconnected_oneDeviceVisible() {
         CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
         CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
@@ -458,7 +458,7 @@
      * Test to verify OnDeviceUnpaired() for a paired hearing Aid device pair.
      */
     @Test
-    public void testOnDeviceUnpaired_bothHearingAidsPaired_removesItsPairFromList() {
+    public void onDeviceUnpaired_bothHearingAidsPaired_removesItsPairFromList() {
         CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
         CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
@@ -488,7 +488,7 @@
      * Test to verify OnDeviceUnpaired() for paired hearing Aid devices which are not a pair.
      */
     @Test
-    public void testOnDeviceUnpaired_bothHearingAidsNotPaired_doesNotRemoveAnyDeviceFromList() {
+    public void onDeviceUnpaired_bothHearingAidsNotPaired_doesNotRemoveAnyDeviceFromList() {
         CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
         CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
@@ -532,7 +532,7 @@
      * Test to verify addDevice() for hearing aid devices with same HiSyncId.
      */
     @Test
-    public void testAddDevice_hearingAidDevicesWithSameHiSyncId_populateInDifferentLists() {
+    public void addDevice_hearingAidDevicesWithSameHiSyncId_populateInDifferentLists() {
         doAnswer((invocation) -> mHearingAidProfile).when(mLocalProfileManager)
             .getHearingAidProfile();
         doAnswer((invocation) -> HISYNCID1).when(mHearingAidProfile).getHiSyncId(mDevice1);
@@ -560,7 +560,7 @@
      * Test to verify addDevice() for hearing aid devices with different HiSyncId.
      */
     @Test
-    public void testAddDevice_hearingAidDevicesWithDifferentHiSyncId_populateInSameList() {
+    public void addDevice_hearingAidDevicesWithDifferentHiSyncId_populateInSameList() {
         doAnswer((invocation) -> mHearingAidProfile).when(mLocalProfileManager)
             .getHearingAidProfile();
         doAnswer((invocation) -> HISYNCID1).when(mHearingAidProfile).getHiSyncId(mDevice1);
@@ -592,7 +592,7 @@
      * Test to verify getHearingAidPairDeviceSummary() for hearing aid devices with same HiSyncId.
      */
     @Test
-    public void testGetHearingAidPairDeviceSummary_bothHearingAidsPaired_returnsSummaryOfPair() {
+    public void getHearingAidPairDeviceSummary_bothHearingAidsPaired_returnsSummaryOfPair() {
         mCachedDevice1.setHiSyncId(HISYNCID1);
         mCachedDevice2.setHiSyncId(HISYNCID1);
         mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
@@ -609,7 +609,7 @@
      * HiSyncId.
      */
     @Test
-    public void testGetHearingAidPairDeviceSummary_bothHearingAidsNotPaired_returnsNull() {
+    public void getHearingAidPairDeviceSummary_bothHearingAidsNotPaired_returnsNull() {
         mCachedDevice1.setHiSyncId(HISYNCID1);
         mCachedDevice2.setHiSyncId(HISYNCID2);
         mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
@@ -625,7 +625,7 @@
      * Test to verify updateHearingAidsDevices().
      */
     @Test
-    public void testUpdateHearingAidDevices_hiSyncIdAvailable_setsHiSyncId() {
+    public void updateHearingAidDevices_hiSyncIdAvailable_setsHiSyncId() {
         doAnswer((invocation) -> mHearingAidProfile).when(mLocalProfileManager)
             .getHearingAidProfile();
         doAnswer((invocation) -> HISYNCID1).when(mHearingAidProfile).getHiSyncId(mDevice1);
@@ -643,7 +643,7 @@
      * Test to verify onBtClassChanged().
      */
     @Test
-    public void testOnBtClassChanged_validBtClass_classChanged() {
+    public void onBtClassChanged_validBtClass_classChanged() {
         CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
         assertThat(cachedDevice1.getBtClass()).isEqualTo(DEVICE_CLASS_1);
@@ -658,7 +658,7 @@
      * Test to verify onDeviceDisappeared().
      */
     @Test
-    public void testOnDeviceDisappeared_deviceBondedUnbonded_unbondedDeviceDisappeared() {
+    public void onDeviceDisappeared_deviceBondedUnbonded_unbondedDeviceDisappeared() {
         CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
 
@@ -673,7 +673,7 @@
      * Test to verify onActiveDeviceChanged().
      */
     @Test
-    public void testOnActiveDeviceChanged_connectedDevices_activeDeviceChanged() {
+    public void onActiveDeviceChanged_connectedDevices_activeDeviceChanged() {
         CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
         CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
@@ -736,7 +736,7 @@
      * Test to verify onActiveDeviceChanged() with A2DP and Hearing Aid.
      */
     @Test
-    public void testOnActiveDeviceChanged_withA2dpAndHearingAid() {
+    public void onActiveDeviceChanged_withA2dpAndHearingAid() {
         CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         assertThat(cachedDevice1).isNotNull();
         CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index c18db11..f6201dd 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -20,6 +20,7 @@
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -79,74 +80,74 @@
     }
 
     @Test
-    public void testGetConnectionSummary_testSingleProfileConnectDisconnect() {
+    public void getConnectionSummary_testSingleProfileConnectDisconnect() {
         // Test without battery level
         // Set PAN profile to be connected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED);
         assertThat(mCachedDevice.getConnectionSummary()).isNull();
 
         // Set PAN profile to be disconnected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
         assertThat(mCachedDevice.getConnectionSummary()).isNull();
 
         // Test with battery level
         mBatteryLevel = 10;
         // Set PAN profile to be connected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED);
         assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("10% battery");
 
         // Set PAN profile to be disconnected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
         assertThat(mCachedDevice.getConnectionSummary()).isNull();
 
         // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
         mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
 
         // Set PAN profile to be connected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED);
         assertThat(mCachedDevice.getConnectionSummary()).isNull();
 
         // Set PAN profile to be disconnected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
         assertThat(mCachedDevice.getConnectionSummary()).isNull();
     }
 
     @Test
-    public void testGetConnectionSummary_testMultipleProfileConnectDisconnect() {
+    public void getConnectionSummary_testMultipleProfileConnectDisconnect() {
         mBatteryLevel = 10;
 
         // Set HFP, A2DP and PAN profile to be connected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
-        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
-        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED);
         assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("10% battery");
 
         // Disconnect HFP only and test connection state summary
-        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
         assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
                 "10% battery");
 
         // Disconnect A2DP only and test connection state summary
-        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
-        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
         assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
                 "10% battery");
 
         // Disconnect both HFP and A2DP and test connection state summary
-        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
         assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
                 "10% battery");
 
         // Disconnect all profiles and test connection state summary
-        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
         assertThat(mCachedDevice.getConnectionSummary()).isNull();
     }
 
     @Test
-    public void testGetConnectionSummary_testSingleProfileActiveDeviceA2dp() {
+    public void getConnectionSummary_testSingleProfileActiveDeviceA2dp() {
         // Test without battery level
         // Set A2DP profile to be connected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
         assertThat(mCachedDevice.getConnectionSummary()).isNull();
 
         // Set device as Active for A2DP and test connection state summary
@@ -159,26 +160,26 @@
                 "Active, 10% battery");
 
         // Set A2DP profile to be disconnected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
         assertThat(mCachedDevice.getConnectionSummary()).isNull();
 
         // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
         mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
         // Set A2DP profile to be connected, Active and test connection state summary
-        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
         mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);
         assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active");
 
         // Set A2DP profile to be disconnected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
         assertThat(mCachedDevice.getConnectionSummary()).isNull();
     }
 
     @Test
-    public void testGetConnectionSummary_testSingleProfileActiveDeviceHfp() {
+    public void getConnectionSummary_testSingleProfileActiveDeviceHfp() {
         // Test without battery level
         // Set HFP profile to be connected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
         assertThat(mCachedDevice.getConnectionSummary()).isNull();
 
         // Set device as Active for HFP and test connection state summary
@@ -193,26 +194,26 @@
                 "Active, 10% battery");
 
         // Set HFP profile to be disconnected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
         assertThat(mCachedDevice.getConnectionSummary()).isNull();
 
         // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
         mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
         // Set HFP profile to be connected, Active and test connection state summary
-        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
         mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET);
         assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active");
 
         // Set HFP profile to be disconnected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
         assertThat(mCachedDevice.getConnectionSummary()).isNull();
     }
 
     @Test
-    public void testGetConnectionSummary_testSingleProfileActiveDeviceHearingAid() {
+    public void getConnectionSummary_testSingleProfileActiveDeviceHearingAid() {
         // Test without battery level
         // Set Hearing Aid profile to be connected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
         assertThat(mCachedDevice.getConnectionSummary()).isNull();
 
         // Set device as Active for Hearing Aid and test connection state summary
@@ -227,11 +228,11 @@
     }
 
     @Test
-    public void testGetConnectionSummary_testMultipleProfilesActiveDevice() {
+    public void getConnectionSummary_testMultipleProfilesActiveDevice() {
         // Test without battery level
         // Set A2DP and HFP profiles to be connected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
-        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
         assertThat(mCachedDevice.getConnectionSummary()).isNull();
 
         // Set device as Active for A2DP and HFP and test connection state summary
@@ -246,14 +247,14 @@
 
         // Disconnect A2DP only and test connection state summary
         mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.A2DP);
-        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
         assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
                 "10% battery");
 
         // Disconnect HFP only and test connection state summary
         mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.HEADSET);
-        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
-        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
         mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);
         assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
                 "Active, 10% battery");
@@ -261,15 +262,15 @@
         // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
         mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
         // Set A2DP and HFP profiles to be connected, Active and test connection state summary
-        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
-        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
         mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);
         mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET);
         assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active");
 
         // Set A2DP and HFP profiles to be disconnected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
-        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
         assertThat(mCachedDevice.getConnectionSummary()).isNull();
     }
 
@@ -277,32 +278,32 @@
     public void getCarConnectionSummary_singleProfileConnectDisconnect() {
         // Test without battery level
         // Set PAN profile to be connected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED);
         assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected");
 
         // Set PAN profile to be disconnected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
         assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
 
         // Test with battery level
         mBatteryLevel = 10;
         // Set PAN profile to be connected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED);
         assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, battery 10%");
 
         // Set PAN profile to be disconnected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
         assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
 
         // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
         mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
 
         // Set PAN profile to be connected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED);
         assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected");
 
         // Set PAN profile to be disconnected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
         assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
     }
 
@@ -311,29 +312,29 @@
         mBatteryLevel = 10;
 
         // Set HFP, A2DP and PAN profile to be connected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
-        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
-        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED);
         assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, battery 10%");
 
         // Disconnect HFP only and test connection state summary
-        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
         assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo(
                 "Connected (no phone), battery 10%");
 
         // Disconnect A2DP only and test connection state summary
-        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
-        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
         assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo(
                 "Connected (no media), battery 10%");
 
         // Disconnect both HFP and A2DP and test connection state summary
-        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
         assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo(
                 "Connected (no phone or media), battery 10%");
 
         // Disconnect all profiles and test connection state summary
-        mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
         assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
     }
 
@@ -341,7 +342,7 @@
     public void getCarConnectionSummary_singleProfileActiveDeviceA2dp() {
         // Test without battery level
         // Set A2DP profile to be connected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
         assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected");
 
         // Set device as Active for A2DP and test connection state summary
@@ -354,18 +355,18 @@
                 "Connected, battery 10%, active (media)");
 
         // Set A2DP profile to be disconnected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
         assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
 
         // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
         mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
         // Set A2DP profile to be connected, Active and test connection state summary
-        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
         mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);
         assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, active (media)");
 
         // Set A2DP profile to be disconnected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
         assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
     }
 
@@ -373,7 +374,7 @@
     public void getCarConnectionSummary_singleProfileActiveDeviceHfp() {
         // Test without battery level
         // Set HFP profile to be connected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
         assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected");
 
         // Set device as Active for HFP and test connection state summary
@@ -386,18 +387,18 @@
                 "Connected, battery 10%, active (phone)");
 
         // Set HFP profile to be disconnected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
         assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
 
         // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
         mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
         // Set HFP profile to be connected, Active and test connection state summary
-        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
         mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET);
         assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, active (phone)");
 
         // Set HFP profile to be disconnected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
         assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
     }
 
@@ -405,7 +406,7 @@
     public void getCarConnectionSummary_singleProfileActiveDeviceHearingAid() {
         // Test without battery level
         // Set Hearing Aid profile to be connected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
         assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected");
 
         // Set device as Active for Hearing Aid and test connection state summary
@@ -414,8 +415,7 @@
 
         // Set Hearing Aid profile to be disconnected and test connection state summary
         mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.HEARING_AID);
-        mCachedDevice.onProfileStateChanged(mHearingAidProfile,
-                BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_DISCONNECTED);
         assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
     }
 
@@ -423,8 +423,8 @@
     public void getCarConnectionSummary_multipleProfilesActiveDevice() {
         // Test without battery level
         // Set A2DP and HFP profiles to be connected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
-        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
         assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected");
 
         // Set device as Active for A2DP and HFP and test connection state summary
@@ -439,14 +439,14 @@
 
         // Disconnect A2DP only and test connection state summary
         mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.A2DP);
-        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
         assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo(
                 "Connected (no media), battery 10%, active (phone)");
 
         // Disconnect HFP only and test connection state summary
         mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.HEADSET);
-        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
-        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
         mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);
         assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo(
                 "Connected (no phone), battery 10%, active (media)");
@@ -454,21 +454,21 @@
         // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
         mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
         // Set A2DP and HFP profiles to be connected, Active and test connection state summary
-        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
-        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
         mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);
         mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET);
         assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, active");
 
         // Set A2DP and HFP profiles to be disconnected and test connection state summary
-        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
-        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
         assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
     }
 
 
     @Test
-    public void testDeviceName_testAliasNameAvailable() {
+    public void deviceName_testAliasNameAvailable() {
         when(mDevice.getAliasName()).thenReturn(DEVICE_ALIAS);
         when(mDevice.getName()).thenReturn(DEVICE_NAME);
         CachedBluetoothDevice cachedBluetoothDevice =
@@ -480,7 +480,7 @@
     }
 
     @Test
-    public void testDeviceName_testNameNotAvailable() {
+    public void deviceName_testNameNotAvailable() {
         CachedBluetoothDevice cachedBluetoothDevice =
                 new CachedBluetoothDevice(mContext, mProfileManager, mDevice);
         // Verify device address is returned on getName
@@ -490,7 +490,7 @@
     }
 
     @Test
-    public void testDeviceName_testRenameDevice() {
+    public void deviceName_testRenameDevice() {
         final String[] alias = {DEVICE_ALIAS};
         doAnswer(invocation -> alias[0]).when(mDevice).getAliasName();
         doAnswer(invocation -> {
@@ -513,7 +513,7 @@
     }
 
     @Test
-    public void testSetActive() {
+    public void setActive() {
         when(mProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
         when(mProfileManager.getHeadsetProfile()).thenReturn(mHfpProfile);
         when(mA2dpProfile.setActiveDevice(any(BluetoothDevice.class))).thenReturn(true);
@@ -521,19 +521,19 @@
 
         assertThat(mCachedDevice.setActive()).isFalse();
 
-        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
         assertThat(mCachedDevice.setActive()).isTrue();
 
-        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
-        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
         assertThat(mCachedDevice.setActive()).isTrue();
 
-        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
         assertThat(mCachedDevice.setActive()).isFalse();
     }
 
     @Test
-    public void testIsA2dpDevice_isA2dpDevice() {
+    public void isA2dpDevice_isA2dpDevice() {
         when(mProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
         when(mA2dpProfile.getConnectionStatus(mDevice)).
                 thenReturn(BluetoothProfile.STATE_CONNECTED);
@@ -542,7 +542,7 @@
     }
 
     @Test
-    public void testIsA2dpDevice_isNotA2dpDevice() {
+    public void isA2dpDevice_isNotA2dpDevice() {
         when(mProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
         when(mA2dpProfile.getConnectionStatus(mDevice)).
                 thenReturn(BluetoothProfile.STATE_DISCONNECTING);
@@ -551,7 +551,7 @@
     }
 
     @Test
-    public void testIsHfpDevice_isHfpDevice() {
+    public void isHfpDevice_isHfpDevice() {
         when(mProfileManager.getHeadsetProfile()).thenReturn(mHfpProfile);
         when(mHfpProfile.getConnectionStatus(mDevice)).
                 thenReturn(BluetoothProfile.STATE_CONNECTED);
@@ -637,4 +637,24 @@
 
         verify(mDevice, never()).setAlias(any());
     }
+
+    @Test
+    public void getProfileConnectionState_nullProfile_returnDisconnected() {
+        assertThat(mCachedDevice.getProfileConnectionState(null)).isEqualTo(
+                BluetoothProfile.STATE_DISCONNECTED);
+    }
+
+    @Test
+    public void getProfileConnectionState_profileConnected_returnConnected() {
+        doReturn(BluetoothProfile.STATE_CONNECTED).when(mA2dpProfile).getConnectionStatus(
+                any(BluetoothDevice.class));
+
+        assertThat(mCachedDevice.getProfileConnectionState(mA2dpProfile)).isEqualTo(
+                BluetoothProfile.STATE_CONNECTED);
+    }
+
+    private void updateProfileStatus(LocalBluetoothProfile profile, int status) {
+        doReturn(status).when(profile).getConnectionStatus(mDevice);
+        mCachedDevice.onProfileStateChanged(profile, status);
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HidDeviceProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HidDeviceProfileTest.java
new file mode 100644
index 0000000..c91ee22
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HidDeviceProfileTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHidDevice;
+import android.bluetooth.BluetoothProfile;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadow.api.Shadow;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(shadows = {ShadowBluetoothAdapter.class})
+public class HidDeviceProfileTest {
+
+    @Mock
+    private CachedBluetoothDeviceManager mDeviceManager;
+    @Mock
+    private LocalBluetoothProfileManager mProfileManager;
+    @Mock
+    private BluetoothHidDevice mService;
+    @Mock
+    private CachedBluetoothDevice mCachedBluetoothDevice;
+    @Mock
+    private BluetoothDevice mBluetoothDevice;
+    private BluetoothProfile.ServiceListener mServiceListener;
+    private HidDeviceProfile mProfile;
+    private ShadowBluetoothAdapter mShadowBluetoothAdapter;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
+        mProfile = new HidDeviceProfile(RuntimeEnvironment.application,
+                mDeviceManager, mProfileManager);
+        mServiceListener = mShadowBluetoothAdapter.getServiceListener();
+        mServiceListener.onServiceConnected(BluetoothProfile.HID_DEVICE, mService);
+    }
+
+    @Test
+    public void connect_shouldReturnFalse() {
+        assertThat(mProfile.connect(mBluetoothDevice)).isFalse();
+    }
+
+    @Test
+    public void disconnect_shouldDisconnectBluetoothHidDevice() {
+        mProfile.disconnect(mBluetoothDevice);
+        verify(mService).disconnect(mBluetoothDevice);
+    }
+
+    @Test
+    public void getConnectionStatus_shouldReturnConnectionState() {
+        when(mService.getConnectionState(mBluetoothDevice)).
+                thenReturn(BluetoothProfile.STATE_CONNECTED);
+        assertThat(mProfile.getConnectionStatus(mBluetoothDevice)).
+                isEqualTo(BluetoothProfile.STATE_CONNECTED);
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/MapClientProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/MapClientProfileTest.java
new file mode 100644
index 0000000..c4c48a8
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/MapClientProfileTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothMapClient;
+import android.bluetooth.BluetoothProfile;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadow.api.Shadow;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(shadows = {ShadowBluetoothAdapter.class})
+public class MapClientProfileTest {
+
+    @Mock
+    private CachedBluetoothDeviceManager mDeviceManager;
+    @Mock
+    private LocalBluetoothProfileManager mProfileManager;
+    @Mock
+    private BluetoothMapClient mService;
+    @Mock
+    private CachedBluetoothDevice mCachedBluetoothDevice;
+    @Mock
+    private BluetoothDevice mBluetoothDevice;
+    private BluetoothProfile.ServiceListener mServiceListener;
+    private MapClientProfile mProfile;
+    private ShadowBluetoothAdapter mShadowBluetoothAdapter;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
+        mProfile = new MapClientProfile(RuntimeEnvironment.application,
+                mDeviceManager, mProfileManager);
+        mServiceListener = mShadowBluetoothAdapter.getServiceListener();
+        mServiceListener.onServiceConnected(BluetoothProfile.MAP_CLIENT, mService);
+    }
+
+    @Test
+    public void connect_shouldConnectBluetoothMapClient() {
+        mProfile.connect(mBluetoothDevice);
+        verify(mService).connect(mBluetoothDevice);
+    }
+
+    @Test
+    public void disconnect_shouldDisconnectBluetoothMapClient() {
+        mProfile.disconnect(mBluetoothDevice);
+        verify(mService).disconnect(mBluetoothDevice);
+    }
+
+    @Test
+    public void getConnectionStatus_shouldReturnConnectionState() {
+        when(mService.getConnectionState(mBluetoothDevice)).
+                thenReturn(BluetoothProfile.STATE_CONNECTED);
+        assertThat(mProfile.getConnectionStatus(mBluetoothDevice)).
+                isEqualTo(BluetoothProfile.STATE_CONNECTED);
+    }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/PbapClientProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/PbapClientProfileTest.java
new file mode 100644
index 0000000..e4a444c
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/PbapClientProfileTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothPbapClient;
+import android.bluetooth.BluetoothProfile;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadow.api.Shadow;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(shadows = {ShadowBluetoothAdapter.class})
+public class PbapClientProfileTest {
+
+    @Mock
+    private CachedBluetoothDeviceManager mDeviceManager;
+    @Mock
+    private LocalBluetoothProfileManager mProfileManager;
+    @Mock
+    private BluetoothPbapClient mService;
+    @Mock
+    private CachedBluetoothDevice mCachedBluetoothDevice;
+    @Mock
+    private BluetoothDevice mBluetoothDevice;
+    private BluetoothProfile.ServiceListener mServiceListener;
+    private PbapClientProfile mProfile;
+    private ShadowBluetoothAdapter mShadowBluetoothAdapter;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
+        mProfile = new PbapClientProfile(RuntimeEnvironment.application,
+                mDeviceManager, mProfileManager);
+        mServiceListener = mShadowBluetoothAdapter.getServiceListener();
+        mServiceListener.onServiceConnected(BluetoothProfile.PBAP_CLIENT, mService);
+    }
+
+    @Test
+    public void connect_shouldConnectBluetoothPbapClient() {
+        mProfile.connect(mBluetoothDevice);
+        verify(mService).connect(mBluetoothDevice);
+    }
+
+    @Test
+    public void disconnect_shouldDisconnectBluetoothPbapClient() {
+        mProfile.disconnect(mBluetoothDevice);
+        verify(mService).disconnect(mBluetoothDevice);
+    }
+
+    @Test
+    public void getConnectionStatus_shouldReturnConnectionState() {
+        when(mService.getConnectionState(mBluetoothDevice)).
+                thenReturn(BluetoothProfile.STATE_CONNECTED);
+        assertThat(mProfile.getConnectionStatus(mBluetoothDevice)).
+                isEqualTo(BluetoothProfile.STATE_CONNECTED);
+    }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
index c23ad79..887c1d5 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
@@ -38,13 +38,13 @@
 import com.android.settingslib.core.lifecycle.events.OnResume;
 import com.android.settingslib.core.lifecycle.events.OnStart;
 import com.android.settingslib.core.lifecycle.events.OnStop;
-import com.android.settingslib.testutils.FragmentTestUtils;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.Robolectric;
 import org.robolectric.android.controller.ActivityController;
+import org.robolectric.shadows.androidx.fragment.FragmentController;
 
 @RunWith(SettingsLibRobolectricTestRunner.class)
 public class LifecycleTest {
@@ -184,7 +184,7 @@
     @Test
     public void runThroughDialogFragmentLifecycles_shouldObserveEverything() {
         final TestDialogFragment fragment = new TestDialogFragment();
-        FragmentTestUtils.startFragment(fragment);
+        FragmentController.setupFragment(fragment);
 
         fragment.onCreateOptionsMenu(null, null);
         fragment.onPrepareOptionsMenu(null);
@@ -208,7 +208,7 @@
     @Test
     public void runThroughFragmentLifecycles_shouldObserveEverything() {
         final TestFragment fragment = new TestFragment();
-        FragmentTestUtils.startFragment(fragment);
+        FragmentController.setupFragment(fragment);
 
         fragment.onCreateOptionsMenu(null, null);
         fragment.onPrepareOptionsMenu(null);
@@ -248,7 +248,7 @@
     @Test
     public void onOptionItemSelectedShortCircuitsIfAnObserverHandlesTheMenuItem() {
         final TestFragment fragment = new TestFragment();
-        FragmentTestUtils.startFragment(fragment);
+        FragmentController.setupFragment(fragment);
 
         final OptionItemAccepter accepter = new OptionItemAccepter();
         fragment.getLifecycle().addObserver(accepter);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java
index a501ffa..40e7386 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java
@@ -77,10 +77,10 @@
 
     @Test
     public void getIcon_hasIconMetadata_returnIcon() {
-        mActivityInfo.metaData.putInt(META_DATA_PREFERENCE_ICON, R.drawable.ic_info);
+        mActivityInfo.metaData.putInt(META_DATA_PREFERENCE_ICON, android.R.drawable.ic_info);
 
         assertThat(mTile.getIcon(RuntimeEnvironment.application).getResId())
-                .isEqualTo(R.drawable.ic_info);
+                .isEqualTo(android.R.drawable.ic_info);
     }
 
     @Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java
new file mode 100644
index 0000000..4c4207b
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.net;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.anyLong;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Matchers.nullable;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.usage.NetworkStatsManager;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.INetworkStatsService;
+import android.net.INetworkStatsSession;
+import android.net.NetworkPolicy;
+import android.net.NetworkStatsHistory;
+import android.net.NetworkTemplate;
+import android.os.RemoteException;
+import android.text.format.DateUtils;
+import android.util.Range;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.util.ReflectionHelpers;
+
+import java.time.ZonedDateTime;
+import java.util.Iterator;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+public class NetworkCycleDataLoaderTest {
+
+    @Mock
+    private NetworkStatsManager mNetworkStatsManager;
+    @Mock
+    private Context mContext;
+    @Mock
+    private NetworkPolicy mPolicy;
+    @Mock
+    private Iterator<Range<ZonedDateTime>> mIterator;
+    @Mock
+    private INetworkStatsService mNetworkStatsService;
+
+    private NetworkCycleDataLoader mLoader;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        when(mContext.getSystemService(Context.NETWORK_STATS_SERVICE))
+            .thenReturn(mNetworkStatsManager);
+        when(mPolicy.cycleIterator()).thenReturn(mIterator);
+    }
+
+    @Test
+    public void loadInBackground_noNetworkPolicy_shouldLoad4WeeksData() {
+        mLoader = spy(new NetworkCycleDataLoader.Builder(mContext).build());
+        doReturn(null).when(mLoader).loadFourWeeksData();
+
+        mLoader.loadInBackground();
+
+        verify(mLoader).loadFourWeeksData();
+    }
+
+    @Test
+    public void loadInBackground_shouldQueryNetworkSummary() throws RemoteException {
+        final int networkType = ConnectivityManager.TYPE_MOBILE;
+        final String subId = "TestSubscriber";
+        final ZonedDateTime now = ZonedDateTime.now();
+        final Range<ZonedDateTime> cycle = new Range<>(now, now);
+        // mock 1 cycle data.
+        // hasNext() will be called internally in next(), hence setting it to return true twice.
+        when(mIterator.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
+        when(mIterator.next()).thenReturn(cycle);
+        mLoader = new NetworkCycleDataLoader.Builder(mContext)
+            .setNetworkPolicy(mPolicy).setNetworkType(networkType).setSubscriberId(subId).build();
+
+        mLoader.loadInBackground();
+
+        verify(mNetworkStatsManager).querySummary(eq(networkType), eq(subId), anyLong(), anyLong());
+    }
+
+    @Test
+    public void loadFourWeeksData_shouldGetUsageForLast4Weeks() throws RemoteException {
+        mLoader = spy(new NetworkCycleDataLoader.Builder(mContext).build());
+        ReflectionHelpers.setField(mLoader, "mNetworkStatsService", mNetworkStatsService);
+        final INetworkStatsSession networkSession = mock(INetworkStatsSession.class);
+        when(mNetworkStatsService.openSession()).thenReturn(networkSession);
+        final NetworkStatsHistory networkHistory = mock(NetworkStatsHistory.class);
+        when(networkSession.getHistoryForNetwork(nullable(NetworkTemplate.class), anyInt())).thenReturn(networkHistory);
+        final long now = System.currentTimeMillis();
+        final long fourWeeksAgo = now - (DateUtils.WEEK_IN_MILLIS * 4);
+        when(networkHistory.getStart()).thenReturn(fourWeeksAgo);
+        when(networkHistory.getEnd()).thenReturn(now);
+
+        mLoader.loadFourWeeksData();
+
+        verify(mLoader).getUsage(eq(fourWeeksAgo), eq(now), any());
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/apppreference/AppPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/apppreference/AppPreferenceTest.java
new file mode 100644
index 0000000..10c9dfb
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/apppreference/AppPreferenceTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.widget.apppreference;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.view.View;
+
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+public class AppPreferenceTest {
+
+    private Context mContext;
+    private View mRootView;
+    private AppPreference mPref;
+    private PreferenceViewHolder mHolder;
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+        mRootView = View.inflate(mContext, R.layout.preference_app, null /* parent */);
+        mHolder = PreferenceViewHolder.createInstanceForTests(mRootView);
+        mPref = new AppPreference(mContext);
+    }
+
+    @Test
+    public void setProgress_showProgress() {
+        mPref.setProgress(1);
+        mPref.onBindViewHolder(mHolder);
+
+        assertThat(mHolder.findViewById(android.R.id.progress).getVisibility())
+                .isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void setSummary_showSummaryContainer() {
+        mPref.setSummary("test");
+        mPref.onBindViewHolder(mHolder);
+
+        assertThat(mHolder.findViewById(R.id.summary_container).getVisibility())
+                .isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void noSummary_hideSummaryContainer() {
+        mPref.setSummary(null);
+        mPref.onBindViewHolder(mHolder);
+
+        assertThat(mHolder.findViewById(R.id.summary_container).getVisibility())
+                .isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void foobar_testName() {
+        float iconSize = mContext.getResources().getDimension(R.dimen.secondary_app_icon_size);
+        assertThat(Float.floatToIntBits(iconSize)).isEqualTo(Float.floatToIntBits(32));
+    }
+}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 290a4f8..3d193db 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2948,7 +2948,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 171;
+            private static final int SETTINGS_VERSION = 172;
 
             private final int mUserId;
 
@@ -3285,8 +3285,8 @@
                 if (currentVersion == 133) {
                     // Version 133: Add default end button behavior
                     final SettingsState systemSettings = getSystemSettingsLocked(userId);
-                    if (systemSettings.getSettingLocked(Settings.System.END_BUTTON_BEHAVIOR) ==
-                            null) {
+                    if (systemSettings.getSettingLocked(Settings.System.END_BUTTON_BEHAVIOR)
+                            .isNull()) {
                         String defaultEndButtonBehavior = Integer.toString(getContext()
                                 .getResources().getInteger(R.integer.def_end_button_behavior));
                         systemSettings.insertSettingLocked(Settings.System.END_BUTTON_BEHAVIOR,
@@ -3900,6 +3900,37 @@
                     currentVersion = 171;
                 }
 
+                if (currentVersion == 171) {
+                    // Version 171: by default, add STREAM_VOICE_CALL to list of streams that can
+                    // be muted.
+                    final SettingsState systemSettings = getSystemSettingsLocked(userId);
+                    final Setting currentSetting = systemSettings.getSettingLocked(
+                              Settings.System.MUTE_STREAMS_AFFECTED);
+                    if (!currentSetting.isNull()) {
+                        try {
+                            int currentSettingIntegerValue = Integer.parseInt(
+                                    currentSetting.getValue());
+                            if ((currentSettingIntegerValue
+                                 & (1 << AudioManager.STREAM_VOICE_CALL)) == 0) {
+                                systemSettings.insertSettingLocked(
+                                    Settings.System.MUTE_STREAMS_AFFECTED,
+                                    Integer.toString(
+                                        currentSettingIntegerValue
+                                        | (1 << AudioManager.STREAM_VOICE_CALL)),
+                                    null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+                            }
+                        } catch (NumberFormatException e) {
+                            // remove the setting in case it is not a valid integer
+                            Slog.w("Failed to parse integer value of MUTE_STREAMS_AFFECTED"
+                                   + "setting, removing setting", e);
+                            systemSettings.deleteSettingLocked(
+                                Settings.System.MUTE_STREAMS_AFFECTED);
+                        }
+
+                    }
+                    currentVersion = 172;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
index b6f51bc..95569dc 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
@@ -613,7 +613,7 @@
             final String name, final String value, final int userId) throws Exception {
         ContentResolver contentResolver = getContext().getContentResolver();
 
-        final Uri settingUri = getBaseUriForType(type);
+        final Uri settingUri = getBaseUriForType(type).buildUpon().appendPath(name).build();
 
         final AtomicBoolean success = new AtomicBoolean();
 
@@ -640,20 +640,22 @@
 
             final long startTimeMillis = SystemClock.uptimeMillis();
             synchronized (mLock) {
-                if (success.get()) {
-                    return;
-                }
-                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
-                if (elapsedTimeMillis > WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS) {
-                    fail("Could not change setting for "
-                            + WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS + " ms");
-                }
-                final long remainingTimeMillis = WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS
-                        - elapsedTimeMillis;
-                try {
-                    mLock.wait(remainingTimeMillis);
-                } catch (InterruptedException ie) {
-                    /* ignore */
+                while (true) {
+                    if (success.get()) {
+                        return;
+                    }
+                    final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+                    if (elapsedTimeMillis > WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS) {
+                        fail("Could not change setting for "
+                                + WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS + " ms");
+                    }
+                    final long remainingTimeMillis = WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS
+                            - elapsedTimeMillis;
+                    try {
+                        mLock.wait(remainingTimeMillis);
+                    } catch (InterruptedException ie) {
+                        /* ignore */
+                    }
                 }
             }
         } finally {
@@ -689,39 +691,50 @@
     }
 
     @Test
-    public void testUpdateLocationProvidersAllowedLocked_enableProviders() throws Exception {
-        setSettingViaFrontEndApiAndAssertSuccessfulChange(
+    public void testLocationModeChanges_viaFrontEndApi() throws Exception {
+        setStringViaFrontEndApiSetting(
                 SETTING_TYPE_SECURE,
                 Settings.Secure.LOCATION_MODE,
                 String.valueOf(Settings.Secure.LOCATION_MODE_OFF),
                 UserHandle.USER_SYSTEM);
-
-        // Enable one provider
-        updateStringViaProviderApiSetting(
-                SETTING_TYPE_SECURE, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "+gps");
-
         assertEquals(
                 "Wrong location providers",
-                "gps",
-                queryStringViaProviderApi(
-                        SETTING_TYPE_SECURE, Settings.Secure.LOCATION_PROVIDERS_ALLOWED));
+                "",
+                getStringViaFrontEndApiSetting(
+                        SETTING_TYPE_SECURE,
+                        Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+                        UserHandle.USER_SYSTEM));
 
-        // Enable a list of providers, including the one that is already enabled
-        updateStringViaProviderApiSetting(
+        setStringViaFrontEndApiSetting(
                 SETTING_TYPE_SECURE,
-                Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
-                "+gps,+network,+network");
+                Settings.Secure.LOCATION_MODE,
+                String.valueOf(Settings.Secure.LOCATION_MODE_BATTERY_SAVING),
+                UserHandle.USER_SYSTEM);
+        assertEquals(
+                "Wrong location providers",
+                "network",
+                getStringViaFrontEndApiSetting(
+                        SETTING_TYPE_SECURE,
+                        Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+                        UserHandle.USER_SYSTEM));
 
+        setStringViaFrontEndApiSetting(
+                SETTING_TYPE_SECURE,
+                Settings.Secure.LOCATION_MODE,
+                String.valueOf(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY),
+                UserHandle.USER_SYSTEM);
         assertEquals(
                 "Wrong location providers",
                 "gps,network",
-                queryStringViaProviderApi(
-                        SETTING_TYPE_SECURE, Settings.Secure.LOCATION_PROVIDERS_ALLOWED));
+                getStringViaFrontEndApiSetting(
+                        SETTING_TYPE_SECURE,
+                        Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+                        UserHandle.USER_SYSTEM));
     }
 
     @Test
-    public void testUpdateLocationProvidersAllowedLocked_disableProviders() throws Exception {
-        setSettingViaFrontEndApiAndAssertSuccessfulChange(
+    public void testLocationProvidersAllowed_disableProviders() throws Exception {
+        setStringViaFrontEndApiSetting(
                 SETTING_TYPE_SECURE,
                 Settings.Secure.LOCATION_MODE,
                 String.valueOf(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY),
@@ -732,7 +745,6 @@
                 SETTING_TYPE_SECURE,
                 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
                 "-gps,-network");
-
         assertEquals(
                 "Wrong location providers",
                 "",
@@ -744,7 +756,6 @@
                 SETTING_TYPE_SECURE,
                 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
                 "-test");
-
         assertEquals(
                 "Wrong location providers",
                 "",
@@ -753,8 +764,8 @@
     }
 
     @Test
-    public void testUpdateLocationProvidersAllowedLocked_enableAndDisable() throws Exception {
-        setSettingViaFrontEndApiAndAssertSuccessfulChange(
+    public void testLocationProvidersAllowed_enableAndDisable() throws Exception {
+        setStringViaFrontEndApiSetting(
                 SETTING_TYPE_SECURE,
                 Settings.Secure.LOCATION_MODE,
                 String.valueOf(Settings.Secure.LOCATION_MODE_OFF),
@@ -775,8 +786,8 @@
     }
 
     @Test
-    public void testUpdateLocationProvidersAllowedLocked_invalidInput() throws Exception {
-        setSettingViaFrontEndApiAndAssertSuccessfulChange(
+    public void testLocationProvidersAllowedLocked_invalidInput() throws Exception {
+        setStringViaFrontEndApiSetting(
                 SETTING_TYPE_SECURE,
                 Settings.Secure.LOCATION_MODE,
                 String.valueOf(Settings.Secure.LOCATION_MODE_OFF),
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index ec35b3d..2530abc 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -44,6 +44,7 @@
 
 import libcore.io.Streams;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.ChooserActivity;
 import com.android.internal.logging.MetricsLogger;
@@ -234,6 +235,7 @@
      */
     private boolean mTakingScreenshot;
 
+    @GuardedBy("sNotificationBundle")
     private static final Bundle sNotificationBundle = new Bundle();
 
     private boolean mIsWatch;
@@ -1059,10 +1061,12 @@
     }
 
     private static Notification.Builder newBaseNotification(Context context) {
-        if (sNotificationBundle.isEmpty()) {
-            // Rename notifcations from "Shell" to "Android System"
-            sNotificationBundle.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
-                    context.getString(com.android.internal.R.string.android_system_label));
+        synchronized (sNotificationBundle) {
+            if (sNotificationBundle.isEmpty()) {
+                // Rename notifcations from "Shell" to "Android System"
+                sNotificationBundle.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
+                        context.getString(com.android.internal.R.string.android_system_label));
+            }
         }
         return new Notification.Builder(context, NOTIFICATION_CHANNEL_ID)
                 .addExtras(sNotificationBundle)
diff --git a/packages/Shell/src/com/android/shell/BugreportStorageProvider.java b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
index 0734e0d..4fbc226 100644
--- a/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
+++ b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
@@ -20,6 +20,7 @@
 import android.database.MatrixCursor;
 import android.database.MatrixCursor.RowBuilder;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.FileUtils;
 import android.os.ParcelFileDescriptor;
@@ -68,6 +69,18 @@
     }
 
     @Override
+    public Cursor queryChildDocuments(
+            String parentDocumentId, String[] projection, String sortOrder)
+            throws FileNotFoundException {
+        final Cursor c = super.queryChildDocuments(parentDocumentId, projection, sortOrder);
+        final Bundle extras = new Bundle();
+        extras.putCharSequence(DocumentsContract.EXTRA_INFO,
+                getContext().getText(R.string.bugreport_confirm));
+        c.setExtras(extras);
+        return c;
+    }
+
+    @Override
     public Cursor queryDocument(String documentId, String[] projection)
             throws FileNotFoundException {
         if (DOC_ID_ROOT.equals(documentId)) {
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index e31dd1e..3725940 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -216,6 +216,7 @@
 
     <protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" />
     <protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" />
+    <protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" />
 
     <application
         android:name=".SystemUIApplication"
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java
index 680f14b..0b1dab1 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java
@@ -38,11 +38,12 @@
 public interface NotificationMenuRowPlugin extends Plugin {
 
     public static final String ACTION = "com.android.systemui.action.PLUGIN_NOTIFICATION_MENU_ROW";
-    public static final int VERSION = 4;
+    public static final int VERSION = 5;
 
     @ProvidesInterface(version = OnMenuEventListener.VERSION)
     public interface OnMenuEventListener {
         public static final int VERSION = 1;
+
         public void onMenuClicked(View row, int x, int y, MenuItem menu);
 
         public void onMenuReset(View row);
@@ -53,6 +54,7 @@
     @ProvidesInterface(version = MenuItem.VERSION)
     public interface MenuItem {
         public static final int VERSION = 1;
+
         public View getMenuView();
 
         public View getGutsView();
@@ -84,34 +86,136 @@
 
     public void setMenuClickListener(OnMenuEventListener listener);
 
-    public void setSwipeActionHelper(NotificationSwipeActionHelper listener);
-
     public void setAppName(String appName);
 
     public void createMenu(ViewGroup parent, StatusBarNotification sbn);
 
-    public View getMenuView();
-
-    public boolean isMenuVisible();
-
     public void resetMenu();
 
-    public void onTranslationUpdate(float translation);
+    public View getMenuView();
 
-    public void onHeightUpdate();
+    /**
+     * Get the target position that a notification row should be snapped open to in order to reveal
+     * the menu. This is generally determined by the number of icons in the notification menu and the
+     * size of each icon. This method accounts for whether the menu appears on the left or ride side
+     * of the parent notification row.
+     *
 
-    public void onNotificationUpdated(StatusBarNotification sbn);
+     * @return an int representing the x-offset in pixels that the notification should snap open to.
+     * Positive values imply that the notification should be offset to the right to reveal the menu,
+     * and negative alues imply that the notification should be offset to the right.
+     */
+    public int getMenuSnapTarget();
 
-    public boolean onTouchEvent(View view, MotionEvent ev, float velocity);
+    /**
+     * Determines whether or not the menu should be shown in response to user input.
+     * @return true if the menu should be shown, false otherwise.
+     */
+    public boolean shouldShowMenu();
+
+    /**
+     * Determines whether the menu is currently visible.
+     * @return true if the menu is visible, false otherwise.
+     */
+    public boolean isMenuVisible();
+
+    /**
+     * Determines whether a given movement is towards or away from the current location of the menu.
+     * @param movement
+     * @return true if the movement is towards the menu, false otherwise.
+     */
+    public boolean isTowardsMenu(float movement);
+
+    /**
+     * Determines whether the menu should snap closed instead of dismissing the
+     * parent notification, as a function of its current state.
+     *
+     * @return true if the menu should snap closed, false otherwise.
+     */
+    public boolean shouldSnapBack();
+
+    /**
+     * Determines whether the menu was previously snapped open to the same side that it is currently
+     * being shown on.
+     * @return true if the menu is snapped open to the same side on which it currently appears,
+     * false otherwise.
+     */
+    public boolean isSnappedAndOnSameSide();
+
+    /**
+     * Determines whether the notification the menu is attached to is able to be dismissed.
+     * @return true if the menu's parent notification is dismissable, false otherwise.
+     */
+    public boolean canBeDismissed();
+
+    /**
+     * Determines whether the menu should remain open given its current state, or snap closed.
+     * @return true if the menu should remain open, false otherwise.
+     */
+    public boolean isWithinSnapMenuThreshold();
+
+    /**
+     * Determines whether the menu has been swiped far enough to snap open.
+     * @return true if the menu has been swiped far enough to open, false otherwise.
+     */
+    public boolean isSwipedEnoughToShowMenu();
 
     public default boolean onInterceptTouchEvent(View view, MotionEvent ev) {
         return false;
     }
 
-    public default boolean useDefaultMenuItems() {
+    public default boolean shouldUseDefaultMenuItems() {
         return false;
     }
 
-    public default void onConfigurationChanged() {
-    }
+    /**
+     * Callback used to signal the menu that its parent's translation has changed.
+     * @param translation The new x-translation of the menu as a position (not an offset).
+     */
+    public void onParentTranslationUpdate(float translation);
+
+    /**
+     * Callback used to signal the menu that its parent's height has changed.
+     */
+    public void onParentHeightUpdate();
+
+    /**
+     * Callback used to signal the menu that its parent notification has been updated.
+     * @param sbn
+     */
+    public void onNotificationUpdated(StatusBarNotification sbn);
+
+    /**
+     * Callback used to signal the menu that a user is moving the parent notification.
+     * @param delta The change in the parent notification's position.
+     */
+    public void onTouchMove(float delta);
+
+    /**
+     * Callback used to signal the menu that a user has begun touching its parent notification.
+     */
+    public void onTouchStart();
+
+    /**
+     * Callback used to signal the menu that a user has finished touching its parent notification.
+     */
+    public void onTouchEnd();
+
+    /**
+     * Callback used to signal the menu that it has been snapped closed.
+     */
+    public void onSnapClosed();
+
+    /**
+     * Callback used to signal the menu that it has been snapped open.
+     */
+    public void onSnapOpen();
+
+    /**
+     * Callback used to signal the menu that its parent notification has been dismissed.
+     */
+    public void onDismiss();
+
+    public default void onConfigurationChanged() { }
+
 }
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationSwipeActionHelper.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationSwipeActionHelper.java
index f6cf035..8db0d02 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationSwipeActionHelper.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationSwipeActionHelper.java
@@ -39,7 +39,7 @@
     /**
      * Call this to snap a notification to provided {@code targetLeft}.
      */
-    public void snap(View animView, float velocity, float targetLeft);
+    public void snapOpen(View animView, int targetLeft, float velocity);
 
     /**
      * Call this to snooze a notification based on the provided {@link SnoozeOption}.
diff --git a/packages/SystemUI/res-keyguard/values-am/strings.xml b/packages/SystemUI/res-keyguard/values-am/strings.xml
index c892ac3..b64e0cf 100644
--- a/packages/SystemUI/res-keyguard/values-am/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-am/strings.xml
@@ -22,8 +22,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="3171996292755059205">"የቁልፍ ጥበቃ"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3420548423949593123">"ፒን ኮድ ይተይቡ"</string>
-    <string name="keyguard_password_enter_puk_code" msgid="670683628782925409">"የሲም ፒዩኬ እና አዲሱን ፒን ኮድ ይተይቡ"</string>
-    <string name="keyguard_password_enter_puk_prompt" msgid="3747778500166059332">"የሲም ፒዩኬ ኮድ"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="670683628782925409">"የሲም PUK እና አዲሱን ፒን ኮድ ይተይቡ"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="3747778500166059332">"የሲም PUK ኮድ"</string>
     <string name="keyguard_password_enter_pin_prompt" msgid="8188243197504453830">"አዲስ የሲም ፒን  ኮድ"</string>
     <string name="keyguard_password_entry_touch_hint" msgid="5790410752696806482"><font size="17">"የይለፍ ቃል ለመተየብ ይንኩ"</font></string>
     <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"ለመክፈት የይለፍ ቃል ይተይቡ"</string>
@@ -48,12 +48,12 @@
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="654102080186420706">"የማይሰራ ሲም ካርድ።"</string>
     <string name="keyguard_permanent_disabled_sim_instructions" msgid="4683178224791318347">"ሲም ካርድዎ እስከመጨረሻው ተሰናክሏል።\n ሌላ ሲም ካርድ ለማግኘት ከገመድ አልባ አገልግሎት አቅራቢዎ ጋር ይገናኙ።"</string>
     <string name="keyguard_sim_locked_message" msgid="953766009432168127">"ሲም ካርድ ተዘግቷል።"</string>
-    <string name="keyguard_sim_puk_locked_message" msgid="1772789643694942073">"ሲም ካርድ በፒዩኬ ተቆልፏል።"</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="1772789643694942073">"ሲም ካርድ በPUK ተቆልፏል።"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="3586601150825821675">"ሲም ካርድን በመክፈት ላይ..."</string>
     <string name="keyguard_accessibility_pin_area" msgid="703175752097279029">"የፒን አካባቢ"</string>
     <string name="keyguard_accessibility_password" msgid="7695303207740941101">"የመሣሪያ ይለፍ ቃል"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="912702510825058921">"የሲም ፒን አካባቢ"</string>
-    <string name="keyguard_accessibility_sim_puk_area" msgid="136979425761438705">"የሲም ፒዩኬ አካባቢ"</string>
+    <string name="keyguard_accessibility_sim_puk_area" msgid="136979425761438705">"የሲም PUK አካባቢ"</string>
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"ቀጣዩ ማንቂያ ለ<xliff:g id="ALARM">%1$s</xliff:g> ተዘጋጅቷል"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"ሰርዝ"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"eSIMን አሰናክል"</string>
@@ -74,14 +74,14 @@
     <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> መሣሪያን ያለሞባይል አገልግሎት ለመጠቀም eSIMን ያሰናክሉ።"</string>
     <string name="kg_pin_instructions" msgid="4069609316644030034">"ፒን ያስገቡ"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"የይለፍ ቃል ያስገቡ"</string>
-    <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"ሲም አሁን ተሰናክሏል። ለመቀጠል የፒዩኬ ኮድ ያስገቡ። ለዝርዝር አገልግሎት አቅራቢን ያግኙ።"</string>
-    <string name="kg_puk_enter_puk_hint_multi" msgid="1373131883510840794">"ሲም «<xliff:g id="CARRIER">%1$s</xliff:g>» አሁን ተሰናክሏል። ለመቀጠል የፒዩኬ ኮድ ያስገቡ። ዝርዝር መረጃን ለማግኘት የተንቀሳቃሽ ስልክ አገልግሎት አቅራቢውን ያነጋግሩ።"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"ሲም አሁን ተሰናክሏል። ለመቀጠል የPUK ኮድ ያስገቡ። ለዝርዝር አገልግሎት አቅራቢን ያግኙ።"</string>
+    <string name="kg_puk_enter_puk_hint_multi" msgid="1373131883510840794">"ሲም «<xliff:g id="CARRIER">%1$s</xliff:g>» አሁን ተሰናክሏል። ለመቀጠል የPUK ኮድ ያስገቡ። ዝርዝር መረጃን ለማግኘት የተንቀሳቃሽ ስልክ አገልግሎት አቅራቢውን ያነጋግሩ።"</string>
     <string name="kg_puk_enter_pin_hint" msgid="3137789674920391087">"የተፈለገውን የፒን ኮድ ያስገቡ"</string>
     <string name="kg_enter_confirm_pin_hint" msgid="3089485999116759671">"የተፈለገውን ፒን ኮድ ያረጋግጡ"</string>
     <string name="kg_sim_unlock_progress_dialog_message" msgid="4471738151810900114">"ሲም ካርድን በመክፈት ላይ..."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="3057533256729513335">"ከ4 እስከ 8 ቁጥሮች የያዘ ፒን ይተይቡ።"</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="6003602401368264144">"የፒዩኬ ኮድ 8 ወይም ከዚያ በላይ ቁጥሮች ሊኖረው ይገባል።"</string>
-    <string name="kg_invalid_puk" msgid="5399287873762592502">"ትክክለኛውን የፒዩኬ ኮድ እንደገና ያስገቡ። ተደጋጋሚ ሙከራዎች ሲሙን እስከመጨረሻው ያሰናክሉታል።"</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="6003602401368264144">"የPUK ኮድ 8 ወይም ከዚያ በላይ ቁጥሮች ሊኖረው ይገባል።"</string>
+    <string name="kg_invalid_puk" msgid="5399287873762592502">"ትክክለኛውን የPUK ኮድ እንደገና ያስገቡ። ተደጋጋሚ ሙከራዎች ሲሙን እስከመጨረሻው ያሰናክሉታል።"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="5672736555427444330">"ፒን ኮዶቹ አይገጣጠሙም"</string>
     <string name="kg_login_too_many_attempts" msgid="6604574268387867255">"በጣም ብዙ የስርዓተ ጥለት ሙከራዎች"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8637788033282252027">"ፒንዎን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ በትክክል አልተየቡም። \n\nበ<xliff:g id="NUMBER_1">%2$d</xliff:g> ሰኮንዶች ውስጥ እንደገና ይሞክሩ።"</string>
@@ -112,7 +112,7 @@
       <item quantity="other">ልክ ያልሆነ የሲም ፒዩኬ ኮድ፣ ሲሙ እስከመጨረሻው የማይሰራ ከመሆኑ በፊት <xliff:g id="NUMBER_1">%d</xliff:g> ሙከራዎች ይቀረዎታል።</item>
     </plurals>
     <string name="kg_password_pin_failed" msgid="8769990811451236223">"የሲም ፒን ክወና አልተሳካም!"</string>
-    <string name="kg_password_puk_failed" msgid="1331621440873439974">"የሲም ፒዩኬ ክወና አልተሳካም!"</string>
+    <string name="kg_password_puk_failed" msgid="1331621440873439974">"የሲም PUK ክወና አልተሳካም!"</string>
     <string name="kg_pin_accepted" msgid="7637293533973802143">"ኮዱ ተቀባይነት አግኝቷል!"</string>
     <string name="keyguard_carrier_default" msgid="4274828292998453695">"ከአገልግሎት መስጫ ክልል ውጪ።"</string>
     <string name="accessibility_ime_switch_button" msgid="2695096475319405612">"የግቤት ስልት ቀይር"</string>
diff --git a/packages/SystemUI/res-keyguard/values-da/strings.xml b/packages/SystemUI/res-keyguard/values-da/strings.xml
index b3b9732..50dc26b 100644
--- a/packages/SystemUI/res-keyguard/values-da/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-da/strings.xml
@@ -117,13 +117,13 @@
     <string name="keyguard_carrier_default" msgid="4274828292998453695">"Ingen dækning."</string>
     <string name="accessibility_ime_switch_button" msgid="2695096475319405612">"Skift indtastningsmetode"</string>
     <string name="airplane_mode" msgid="3807209033737676010">"Flytilstand"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="7246972020562621506">"Der skal angives et mønster efter genstart af enheden"</string>
+    <string name="kg_prompt_reason_restart_pattern" msgid="7246972020562621506">"Du skal angive et mønster, når du har genstartet enheden"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="6303592361322290145">"Der skal indtastes en pinkode efter genstart af enheden"</string>
     <string name="kg_prompt_reason_restart_password" msgid="6984641181515902406">"Der skal indtastes en adgangskode efter genstart af enheden"</string>
     <string name="kg_prompt_reason_timeout_pattern" msgid="5304487696073914063">"Der kræves et mønster som ekstra beskyttelse"</string>
     <string name="kg_prompt_reason_timeout_pin" msgid="8851462864335757813">"Der kræves en pinkode som ekstra beskyttelse"</string>
     <string name="kg_prompt_reason_timeout_password" msgid="6563904839641583441">"Der kræves en adgangskode som ekstra beskyttelse"</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3398054847288438444">"Der skal angives et mønster, når du skifter profil"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3398054847288438444">"Du skal angive et mønster, når du skifter profil"</string>
     <string name="kg_prompt_reason_switch_profiles_pin" msgid="7426368139226961699">"Der skal indtastes en pinkode, når du skifter profil"</string>
     <string name="kg_prompt_reason_switch_profiles_password" msgid="8383831046318421845">"Der skal indtastes en adgangskode, når du skifter profil"</string>
     <string name="kg_prompt_reason_device_admin" msgid="3452168247888906179">"Enheden er blevet låst af administratoren"</string>
diff --git a/packages/SystemUI/res-keyguard/values-fr/strings.xml b/packages/SystemUI/res-keyguard/values-fr/strings.xml
index d5e36ce..f0c7e92 100644
--- a/packages/SystemUI/res-keyguard/values-fr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr/strings.xml
@@ -34,9 +34,9 @@
     <string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Le code est incorrect."</string>
     <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Carte non valide."</string>
     <string name="keyguard_charged" msgid="3316115607283493413">"Complètement chargée"</string>
-    <string name="keyguard_plugged_in" msgid="3161102098900158923">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Rechargement…"</string>
-    <string name="keyguard_plugged_in_charging_fast" msgid="3684592786276709342">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Rechargement rapide…"</string>
-    <string name="keyguard_plugged_in_charging_slowly" msgid="509533586841478405">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Rechargement lent…"</string>
+    <string name="keyguard_plugged_in" msgid="3161102098900158923">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Recharge…"</string>
+    <string name="keyguard_plugged_in_charging_fast" msgid="3684592786276709342">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Recharge rapide…"</string>
+    <string name="keyguard_plugged_in_charging_slowly" msgid="509533586841478405">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Recharge lente…"</string>
     <string name="keyguard_low_battery" msgid="9218432555787624490">"Branchez votre chargeur."</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8566679946700751371">"Appuyez sur \"Menu\" pour déverrouiller le clavier."</string>
     <string name="keyguard_network_locked_message" msgid="6743537524631420759">"Réseau verrouillé"</string>
diff --git a/packages/SystemUI/res/drawable/fingerprint_dialog_bg.xml b/packages/SystemUI/res/drawable/biometric_dialog_bg.xml
similarity index 80%
rename from packages/SystemUI/res/drawable/fingerprint_dialog_bg.xml
rename to packages/SystemUI/res/drawable/biometric_dialog_bg.xml
index 221f170..335448d 100644
--- a/packages/SystemUI/res/drawable/fingerprint_dialog_bg.xml
+++ b/packages/SystemUI/res/drawable/biometric_dialog_bg.xml
@@ -17,10 +17,10 @@
   -->
 
 <shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <solid android:color="@color/fingerprint_dialog_bg_color" />
+    <solid android:color="@color/biometric_dialog_bg_color" />
     <corners android:radius="1dp"
-        android:topLeftRadius="@dimen/fingerprint_dialog_corner_size"
-        android:topRightRadius="@dimen/fingerprint_dialog_corner_size"
+        android:topLeftRadius="@dimen/biometric_dialog_corner_size"
+        android:topRightRadius="@dimen/biometric_dialog_corner_size"
         android:bottomLeftRadius="0dp"
         android:bottomRightRadius="0dp"/>
 </shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/face_dialog_icon.xml b/packages/SystemUI/res/drawable/face_dialog_icon.xml
new file mode 100644
index 0000000..6d28b5a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/face_dialog_icon.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:width="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path android:fillColor="#000" android:pathData="M9,11.75A1.25,1.25 0 0,0 7.75,13A1.25,1.25 0 0,0 9,14.25A1.25,1.25 0 0,0 10.25,13A1.25,1.25 0 0,0 9,11.75M15,11.75A1.25,1.25 0 0,0 13.75,13A1.25,1.25 0 0,0 15,14.25A1.25,1.25 0 0,0 16.25,13A1.25,1.25 0 0,0 15,11.75M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,20C7.59,20 4,16.41 4,12C4,11.71 4,11.42 4.05,11.14C6.41,10.09 8.28,8.16 9.26,5.77C11.07,8.33 14.05,10 17.42,10C18.2,10 18.95,9.91 19.67,9.74C19.88,10.45 20,11.21 20,12C20,16.41 16.41,20 12,20Z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml b/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml
index 83c1949..05fd467 100644
--- a/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml
+++ b/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml
@@ -36,7 +36,7 @@
                         android:name="_R_G_L_2_G_D_0_P_0"
                         android:pathData=" M-25.36 -24.41 C-25.93,-24.31 -26.49,-24.27 -26.81,-24.27 C-28.11,-24.27 -29.35,-24.62 -30.43,-25.4 C-32.11,-26.6 -33.2,-28.57 -33.2,-30.79 "
                         android:strokeAlpha="1"
-                        android:strokeColor="@color/fingerprint_dialog_fingerprint_color"
+                        android:strokeColor="@color/biometric_dialog_biometric_color"
                         android:strokeLineCap="round"
                         android:strokeLineJoin="round"
                         android:strokeWidth="1.45"
@@ -47,7 +47,7 @@
                         android:name="_R_G_L_2_G_D_1_P_0"
                         android:pathData=" M-36.14 -21.78 C-37.15,-22.98 -37.72,-23.7 -38.51,-25.29 C-39.33,-26.94 -39.82,-28.78 -39.82,-30.77 C-39.82,-34.43 -36.85,-37.4 -33.19,-37.4 C-29.52,-37.4 -26.55,-34.43 -26.55,-30.77 "
                         android:strokeAlpha="1"
-                        android:strokeColor="@color/fingerprint_dialog_fingerprint_color"
+                        android:strokeColor="@color/biometric_dialog_biometric_color"
                         android:strokeLineCap="round"
                         android:strokeLineJoin="round"
                         android:strokeWidth="1.45"
@@ -58,7 +58,7 @@
                         android:name="_R_G_L_2_G_D_2_P_0"
                         android:pathData=" M-42.19 -25.68 C-42.95,-27.82 -43.09,-29.54 -43.09,-30.8 C-43.09,-32.27 -42.84,-33.65 -42.27,-34.9 C-40.71,-38.35 -37.24,-40.75 -33.2,-40.75 C-27.71,-40.75 -23.26,-36.3 -23.26,-30.8 C-23.26,-28.97 -24.74,-27.49 -26.57,-27.49 C-28.4,-27.49 -29.89,-28.97 -29.89,-30.8 C-29.89,-32.64 -31.37,-34.12 -33.2,-34.12 C-35.04,-34.12 -36.52,-32.64 -36.52,-30.8 C-36.52,-28.23 -35.53,-25.92 -33.92,-24.22 C-32.69,-22.93 -31.48,-22.12 -29.44,-21.53 "
                         android:strokeAlpha="1"
-                        android:strokeColor="@color/fingerprint_dialog_fingerprint_color"
+                        android:strokeColor="@color/biometric_dialog_biometric_color"
                         android:strokeLineCap="round"
                         android:strokeLineJoin="round"
                         android:strokeWidth="1.45"
@@ -69,7 +69,7 @@
                         android:name="_R_G_L_2_G_D_3_P_0"
                         android:pathData=" M-44.06 -38.17 C-42.87,-39.94 -41.39,-41.41 -39.51,-42.44 C-37.62,-43.47 -35.46,-44.05 -33.16,-44.05 C-30.88,-44.05 -28.72,-43.47 -26.85,-42.45 C-24.97,-41.43 -23.48,-39.97 -22.29,-38.21 "
                         android:strokeAlpha="1"
-                        android:strokeColor="@color/fingerprint_dialog_fingerprint_color"
+                        android:strokeColor="@color/biometric_dialog_biometric_color"
                         android:strokeLineCap="round"
                         android:strokeLineJoin="round"
                         android:strokeWidth="1.45"
@@ -80,7 +80,7 @@
                         android:name="_R_G_L_2_G_D_4_P_0"
                         android:pathData=" M-25.72 -45.45 C-27.99,-46.76 -30.43,-47.52 -33.28,-47.52 C-36.13,-47.52 -38.51,-46.74 -40.62,-45.45 "
                         android:strokeAlpha="1"
-                        android:strokeColor="@color/fingerprint_dialog_fingerprint_color"
+                        android:strokeColor="@color/biometric_dialog_biometric_color"
                         android:strokeLineCap="round"
                         android:strokeLineJoin="round"
                         android:strokeWidth="1.45"
@@ -97,7 +97,7 @@
                         android:name="_R_G_L_1_G_D_0_P_0"
                         android:pathData=" M0 -9 C4.97,-9 9,-4.97 9,0 C9,4.97 4.97,9 0,9 C-4.97,9 -9,4.97 -9,0 C-9,-4.97 -4.97,-9 0,-9c "
                         android:strokeAlpha="1"
-                        android:strokeColor="@color/fingerprint_dialog_error_color"
+                        android:strokeColor="@color/biometric_dialog_error_color"
                         android:strokeLineCap="round"
                         android:strokeLineJoin="round"
                         android:strokeWidth="2"
@@ -118,7 +118,7 @@
                         <path
                             android:name="_R_G_L_0_G_D_0_P_0"
                             android:fillAlpha="1"
-                            android:fillColor="@color/fingerprint_dialog_error_color"
+                            android:fillColor="@color/biometric_dialog_error_color"
                             android:fillType="nonZero"
                             android:pathData=" M1.1 3.94 C1.1,4.55 0.61,5.04 0,5.04 C-0.61,5.04 -1.1,4.55 -1.1,3.94 C-1.1,3.33 -0.61,2.84 0,2.84 C0.61,2.84 1.1,3.33 1.1,3.94c " />
                     </group>
@@ -131,7 +131,7 @@
                         <path
                             android:name="_R_G_L_0_G_D_0_P_1"
                             android:fillAlpha="1"
-                            android:fillColor="@color/fingerprint_dialog_error_color"
+                            android:fillColor="@color/biometric_dialog_error_color"
                             android:fillType="nonZero"
                             android:pathData=" M1 -4.06 C1,-4.06 1,-0.06 1,-0.06 C1,0.49 0.55,0.94 0,0.94 C-0.55,0.94 -1,0.49 -1,-0.06 C-1,-0.06 -1,-4.06 -1,-4.06 C-1,-4.61 -0.55,-5.06 0,-5.06 C0.55,-5.06 1,-4.61 1,-4.06c " />
                     </group>
diff --git a/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml b/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml
index f682f87..fd0ab22 100644
--- a/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml
+++ b/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml
@@ -36,7 +36,7 @@
                         android:name="_R_G_L_3_G_D_0_P_0"
                         android:pathData=" M-25.36 -24.41 C-25.93,-24.31 -26.49,-24.27 -26.81,-24.27 C-28.11,-24.27 -29.35,-24.62 -30.43,-25.4 C-32.11,-26.6 -33.2,-28.57 -33.2,-30.79 "
                         android:strokeAlpha="1"
-                        android:strokeColor="@color/fingerprint_dialog_fingerprint_color"
+                        android:strokeColor="@color/biometric_dialog_biometric_color"
                         android:strokeLineCap="round"
                         android:strokeLineJoin="round"
                         android:strokeWidth="1.45"
@@ -47,7 +47,7 @@
                         android:name="_R_G_L_3_G_D_1_P_0"
                         android:pathData=" M-36.14 -21.78 C-37.15,-22.98 -37.72,-23.7 -38.51,-25.29 C-39.33,-26.94 -39.82,-28.78 -39.82,-30.77 C-39.82,-34.43 -36.85,-37.4 -33.19,-37.4 C-29.52,-37.4 -26.55,-34.43 -26.55,-30.77 "
                         android:strokeAlpha="1"
-                        android:strokeColor="@color/fingerprint_dialog_fingerprint_color"
+                        android:strokeColor="@color/biometric_dialog_biometric_color"
                         android:strokeLineCap="round"
                         android:strokeLineJoin="round"
                         android:strokeWidth="1.45"
@@ -58,7 +58,7 @@
                         android:name="_R_G_L_3_G_D_2_P_0"
                         android:pathData=" M-42.19 -25.68 C-42.95,-27.82 -43.09,-29.54 -43.09,-30.8 C-43.09,-32.27 -42.84,-33.65 -42.27,-34.9 C-40.71,-38.35 -37.24,-40.75 -33.2,-40.75 C-27.71,-40.75 -23.26,-36.3 -23.26,-30.8 C-23.26,-28.97 -24.74,-27.49 -26.57,-27.49 C-28.4,-27.49 -29.89,-28.97 -29.89,-30.8 C-29.89,-32.64 -31.37,-34.12 -33.2,-34.12 C-35.04,-34.12 -36.52,-32.64 -36.52,-30.8 C-36.52,-28.23 -35.53,-25.92 -33.92,-24.22 C-32.69,-22.93 -31.48,-22.12 -29.44,-21.53 "
                         android:strokeAlpha="1"
-                        android:strokeColor="@color/fingerprint_dialog_fingerprint_color"
+                        android:strokeColor="@color/biometric_dialog_biometric_color"
                         android:strokeLineCap="round"
                         android:strokeLineJoin="round"
                         android:strokeWidth="1.45"
@@ -69,7 +69,7 @@
                         android:name="_R_G_L_3_G_D_3_P_0"
                         android:pathData=" M-44.06 -38.17 C-42.87,-39.94 -41.39,-41.41 -39.51,-42.44 C-37.62,-43.47 -35.46,-44.05 -33.16,-44.05 C-30.88,-44.05 -28.72,-43.47 -26.85,-42.45 C-24.97,-41.43 -23.48,-39.97 -22.29,-38.21 "
                         android:strokeAlpha="1"
-                        android:strokeColor="@color/fingerprint_dialog_fingerprint_color"
+                        android:strokeColor="@color/biometric_dialog_biometric_color"
                         android:strokeLineCap="round"
                         android:strokeLineJoin="round"
                         android:strokeWidth="1.45"
@@ -80,7 +80,7 @@
                         android:name="_R_G_L_3_G_D_4_P_0"
                         android:pathData=" M-25.72 -45.45 C-27.99,-46.76 -30.43,-47.52 -33.28,-47.52 C-36.13,-47.52 -38.51,-46.74 -40.62,-45.45 "
                         android:strokeAlpha="1"
-                        android:strokeColor="@color/fingerprint_dialog_fingerprint_color"
+                        android:strokeColor="@color/biometric_dialog_biometric_color"
                         android:strokeLineCap="round"
                         android:strokeLineJoin="round"
                         android:strokeWidth="1.45"
@@ -101,7 +101,7 @@
                         android:name="_R_G_L_2_G_D_0_P_0"
                         android:pathData=" M-25.36 -24.41 C-25.93,-24.31 -26.49,-24.27 -26.81,-24.27 C-28.11,-24.27 -29.35,-24.62 -30.43,-25.4 C-32.11,-26.6 -33.2,-28.57 -33.2,-30.79 "
                         android:strokeAlpha="1"
-                        android:strokeColor="@color/fingerprint_dialog_error_color"
+                        android:strokeColor="@color/biometric_dialog_error_color"
                         android:strokeLineCap="round"
                         android:strokeLineJoin="round"
                         android:strokeWidth="1.45"
@@ -112,7 +112,7 @@
                         android:name="_R_G_L_2_G_D_1_P_0"
                         android:pathData=" M-36.14 -21.78 C-37.15,-22.98 -37.72,-23.7 -38.51,-25.29 C-39.33,-26.94 -39.82,-28.78 -39.82,-30.77 C-39.82,-34.43 -36.85,-37.4 -33.19,-37.4 C-29.52,-37.4 -26.55,-34.43 -26.55,-30.77 "
                         android:strokeAlpha="1"
-                        android:strokeColor="@color/fingerprint_dialog_error_color"
+                        android:strokeColor="@color/biometric_dialog_error_color"
                         android:strokeLineCap="round"
                         android:strokeLineJoin="round"
                         android:strokeWidth="1.45"
@@ -123,7 +123,7 @@
                         android:name="_R_G_L_2_G_D_2_P_0"
                         android:pathData=" M-42.19 -25.68 C-42.95,-27.82 -43.09,-29.54 -43.09,-30.8 C-43.09,-32.27 -42.84,-33.65 -42.27,-34.9 C-40.71,-38.35 -37.24,-40.75 -33.2,-40.75 C-27.71,-40.75 -23.26,-36.3 -23.26,-30.8 C-23.26,-28.97 -24.74,-27.49 -26.57,-27.49 C-28.4,-27.49 -29.89,-28.97 -29.89,-30.8 C-29.89,-32.64 -31.37,-34.12 -33.2,-34.12 C-35.04,-34.12 -36.52,-32.64 -36.52,-30.8 C-36.52,-28.23 -35.53,-25.92 -33.92,-24.22 C-32.69,-22.93 -31.48,-22.12 -29.44,-21.53 "
                         android:strokeAlpha="1"
-                        android:strokeColor="@color/fingerprint_dialog_error_color"
+                        android:strokeColor="@color/biometric_dialog_error_color"
                         android:strokeLineCap="round"
                         android:strokeLineJoin="round"
                         android:strokeWidth="1.45"
@@ -134,7 +134,7 @@
                         android:name="_R_G_L_2_G_D_3_P_0"
                         android:pathData=" M-44.06 -38.17 C-42.87,-39.94 -41.39,-41.41 -39.51,-42.44 C-37.62,-43.47 -35.46,-44.05 -33.16,-44.05 C-30.88,-44.05 -28.72,-43.47 -26.85,-42.45 C-24.97,-41.43 -23.48,-39.97 -22.29,-38.21 "
                         android:strokeAlpha="1"
-                        android:strokeColor="@color/fingerprint_dialog_error_color"
+                        android:strokeColor="@color/biometric_dialog_error_color"
                         android:strokeLineCap="round"
                         android:strokeLineJoin="round"
                         android:strokeWidth="1.45"
@@ -145,7 +145,7 @@
                         android:name="_R_G_L_2_G_D_4_P_0"
                         android:pathData=" M-25.72 -45.45 C-27.99,-46.76 -30.43,-47.52 -33.28,-47.52 C-36.13,-47.52 -38.51,-46.74 -40.62,-45.45 "
                         android:strokeAlpha="1"
-                        android:strokeColor="@color/fingerprint_dialog_error_color"
+                        android:strokeColor="@color/biometric_dialog_error_color"
                         android:strokeLineCap="round"
                         android:strokeLineJoin="round"
                         android:strokeWidth="1.45"
@@ -162,7 +162,7 @@
                         android:name="_R_G_L_1_G_D_0_P_0"
                         android:pathData=" M0 -9 C4.97,-9 9,-4.97 9,0 C9,4.97 4.97,9 0,9 C-4.97,9 -9,4.97 -9,0 C-9,-4.97 -4.97,-9 0,-9c "
                         android:strokeAlpha="1"
-                        android:strokeColor="@color/fingerprint_dialog_error_color"
+                        android:strokeColor="@color/biometric_dialog_error_color"
                         android:strokeLineCap="round"
                         android:strokeLineJoin="round"
                         android:strokeWidth="2"
@@ -183,7 +183,7 @@
                         <path
                             android:name="_R_G_L_0_G_D_0_P_0"
                             android:fillAlpha="1"
-                            android:fillColor="@color/fingerprint_dialog_error_color"
+                            android:fillColor="@color/biometric_dialog_error_color"
                             android:fillType="nonZero"
                             android:pathData=" M1.1 3.94 C1.1,4.55 0.61,5.04 0,5.04 C-0.61,5.04 -1.1,4.55 -1.1,3.94 C-1.1,3.33 -0.61,2.84 0,2.84 C0.61,2.84 1.1,3.33 1.1,3.94c " />
                     </group>
@@ -196,7 +196,7 @@
                         <path
                             android:name="_R_G_L_0_G_D_0_P_1"
                             android:fillAlpha="1"
-                            android:fillColor="@color/fingerprint_dialog_error_color"
+                            android:fillColor="@color/biometric_dialog_error_color"
                             android:fillType="nonZero"
                             android:pathData=" M1 -4.06 C1,-4.06 1,-0.06 1,-0.06 C1,0.49 0.55,0.94 0,0.94 C-0.55,0.94 -1,0.49 -1,-0.06 C-1,-0.06 -1,-4.06 -1,-4.06 C-1,-4.61 -0.55,-5.06 0,-5.06 C0.55,-5.06 1,-4.61 1,-4.06c " />
                     </group>
diff --git a/packages/SystemUI/res/layout/fingerprint_dialog.xml b/packages/SystemUI/res/layout/biometric_dialog.xml
similarity index 78%
rename from packages/SystemUI/res/layout/fingerprint_dialog.xml
rename to packages/SystemUI/res/layout/biometric_dialog.xml
index 1bdaf6e..0417e2e 100644
--- a/packages/SystemUI/res/layout/fingerprint_dialog.xml
+++ b/packages/SystemUI/res/layout/biometric_dialog.xml
@@ -19,7 +19,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:gravity="bottom"
-    android:background="@color/fingerprint_dialog_dim_color"
+    android:background="@color/biometric_dialog_dim_color"
     android:orientation="vertical">
 
     <!-- This is not a Space since Spaces cannot be clicked -->
@@ -47,7 +47,7 @@
             android:layout_height="wrap_content"
             android:orientation="vertical"
             android:elevation="2dp"
-            android:background="@drawable/fingerprint_dialog_bg">
+            android:background="@drawable/biometric_dialog_bg">
 
             <TextView
                 android:id="@+id/title"
@@ -57,13 +57,13 @@
                 android:layout_marginEnd="24dp"
                 android:layout_marginStart="24dp"
                 android:layout_marginTop="24dp"
-                android:gravity="@integer/fingerprint_dialog_text_gravity"
+                android:gravity="@integer/biometric_dialog_text_gravity"
                 android:textSize="20sp"
                 android:maxLines="1"
                 android:singleLine="true"
                 android:ellipsize="marquee"
                 android:marqueeRepeatLimit="marquee_forever"
-                android:textColor="@color/fingerprint_dialog_text_dark_color"/>
+                android:textColor="@color/biometric_dialog_text_dark_color"/>
 
             <TextView
                 android:id="@+id/subtitle"
@@ -72,13 +72,13 @@
                 android:layout_marginTop="8dp"
                 android:layout_marginStart="24dp"
                 android:layout_marginEnd="24dp"
-                android:gravity="@integer/fingerprint_dialog_text_gravity"
+                android:gravity="@integer/biometric_dialog_text_gravity"
                 android:textSize="16sp"
                 android:maxLines="1"
                 android:singleLine="true"
                 android:ellipsize="marquee"
                 android:marqueeRepeatLimit="marquee_forever"
-                android:textColor="@color/fingerprint_dialog_text_dark_color"/>
+                android:textColor="@color/biometric_dialog_text_dark_color"/>
 
             <TextView
                 android:id="@+id/description"
@@ -86,20 +86,19 @@
                 android:layout_height="wrap_content"
                 android:layout_marginEnd="24dp"
                 android:layout_marginStart="24dp"
-                android:gravity="@integer/fingerprint_dialog_text_gravity"
+                android:gravity="@integer/biometric_dialog_text_gravity"
                 android:paddingTop="8dp"
                 android:textSize="16sp"
                 android:maxLines="4"
-                android:textColor="@color/fingerprint_dialog_text_dark_color"/>
+                android:textColor="@color/biometric_dialog_text_dark_color"/>
 
             <ImageView
-                android:id="@+id/fingerprint_icon"
-                android:layout_width="@dimen/fingerprint_dialog_fp_icon_size"
-                android:layout_height="@dimen/fingerprint_dialog_fp_icon_size"
+                android:id="@+id/biometric_icon"
+                android:layout_width="@dimen/biometric_dialog_biometric_icon_size"
+                android:layout_height="@dimen/biometric_dialog_biometric_icon_size"
                 android:layout_gravity="center_horizontal"
                 android:layout_marginTop="48dp"
-                android:scaleType="fitXY"
-                android:contentDescription="@string/accessibility_fingerprint_dialog_fingerprint_icon" />
+                android:scaleType="fitXY" />
 
             <TextView
                 android:id="@+id/error"
@@ -112,9 +111,8 @@
                 android:textSize="12sp"
                 android:gravity="center_horizontal"
                 android:accessibilityLiveRegion="polite"
-                android:text="@string/fingerprint_dialog_touch_sensor"
-                android:contentDescription="@string/accessibility_fingerprint_dialog_help_area"
-                android:textColor="@color/fingerprint_dialog_text_light_color"/>
+                android:contentDescription="@string/accessibility_biometric_dialog_help_area"
+                android:textColor="@color/biometric_dialog_text_light_color"/>
 
             <LinearLayout
                 android:layout_width="match_parent"
@@ -125,7 +123,7 @@
                 android:orientation="horizontal"
                 android:measureWithLargestChild="true">
                 <Space android:id="@+id/leftSpacer"
-                    android:layout_width="24dp"
+                    android:layout_width="12dp"
                     android:layout_height="match_parent"
                     android:visibility="visible" />
                 <!-- Negative Button -->
@@ -133,20 +131,26 @@
                     android:layout_width="wrap_content"
                     android:layout_height="match_parent"
                     style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
-                    android:layout_marginStart="-12dp"
-                    android:gravity="start|center_vertical"
+                    android:gravity="center"
                     android:maxLines="2" />
+                <Space android:id="@+id/middleSpacer"
+                    android:layout_width="0dp"
+                    android:layout_height="match_parent"
+                    android:layout_weight="1"
+                    android:visibility="visible" />
                 <!-- Positive Button -->
                 <Button android:id="@+id/button1"
                     android:layout_width="wrap_content"
                     android:layout_height="match_parent"
-                    style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
-                    android:layout_marginEnd="12dp"
-                    android:maxLines="2" />
+                    style="@*android:style/Widget.DeviceDefault.Button.Colored"
+                    android:gravity="center"
+                    android:maxLines="2"
+                    android:text="@string/biometric_dialog_confirm"
+                    android:visibility="gone"/>
                 <Space android:id="@+id/rightSpacer"
-                    android:layout_width="24dip"
+                    android:layout_width="12dip"
                     android:layout_height="match_parent"
-                    android:visibility="gone" />
+                    android:visibility="visible" />
             </LinearLayout>
         </LinearLayout>
 
diff --git a/packages/SystemUI/res/layout/menu_ime.xml b/packages/SystemUI/res/layout/menu_ime.xml
index b047efb..8a3a0b1 100644
--- a/packages/SystemUI/res/layout/menu_ime.xml
+++ b/packages/SystemUI/res/layout/menu_ime.xml
@@ -19,7 +19,6 @@
     android:id="@+id/menu_container"
     android:layout_width="@dimen/navigation_key_width"
     android:layout_height="match_parent"
-    android:focusable="false"
     android:importantForAccessibility="no"
     >
     <!-- Use nav button width & height=match_parent for parent FrameLayout and buttons because they
diff --git a/packages/SystemUI/res/layout/operator_name.xml b/packages/SystemUI/res/layout/operator_name.xml
index c4f75e9..015e30a 100644
--- a/packages/SystemUI/res/layout/operator_name.xml
+++ b/packages/SystemUI/res/layout/operator_name.xml
@@ -27,5 +27,6 @@
         android:maxLength="20"
         android:gravity="center_vertical|start"
         android:textAppearance="?android:attr/textAppearanceSmall"
-        android:singleLine="true" />
+        android:singleLine="true"
+        android:paddingEnd="5dp" />
 </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
diff --git a/packages/SystemUI/res/layout/qs_customize_panel_content.xml b/packages/SystemUI/res/layout/qs_customize_panel_content.xml
index bb67c54..87b4551 100644
--- a/packages/SystemUI/res/layout/qs_customize_panel_content.xml
+++ b/packages/SystemUI/res/layout/qs_customize_panel_content.xml
@@ -17,6 +17,7 @@
 
 <merge xmlns:android="http://schemas.android.com/apk/res/android">->
     <View
+        android:id="@+id/customizer_transparent_view"
         android:layout_width="match_parent"
         android:layout_height="@*android:dimen/quick_qs_offset_height"
         android:background="@android:color/transparent" />
diff --git a/packages/SystemUI/res/layout/qs_detail_buttons.xml b/packages/SystemUI/res/layout/qs_detail_buttons.xml
index 03ed62b..75f43f9 100644
--- a/packages/SystemUI/res/layout/qs_detail_buttons.xml
+++ b/packages/SystemUI/res/layout/qs_detail_buttons.xml
@@ -26,6 +26,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginEnd="8dp"
+        android:minHeight="48dp"
         android:minWidth="132dp"
         android:textAppearance="@style/TextAppearance.QS.DetailButton"
         android:focusable="true" />
@@ -35,6 +36,7 @@
         style="@style/QSBorderlessButton"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:minHeight="48dp"
         android:minWidth="88dp"
         android:textAppearance="@style/TextAppearance.QS.DetailButton"
         android:focusable="true"/>
diff --git a/packages/SystemUI/res/layout/qs_paged_page.xml b/packages/SystemUI/res/layout/qs_paged_page.xml
index 07f0c83..a8960d9 100644
--- a/packages/SystemUI/res/layout/qs_paged_page.xml
+++ b/packages/SystemUI/res/layout/qs_paged_page.xml
@@ -19,7 +19,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/tile_page"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content"
+    android:layout_height="match_parent"
     android:paddingStart="@dimen/notification_side_paddings"
     android:paddingEnd="@dimen/notification_side_paddings"
     android:clipChildren="false"
diff --git a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
index e96a09b..11a0187 100644
--- a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
+++ b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
@@ -19,6 +19,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    android:layout_weight="1"
     android:clipChildren="false"
     android:clipToPadding="false"
     android:paddingBottom="@dimen/qs_paged_tile_layout_padding_bottom">
diff --git a/packages/SystemUI/res/layout/recents_onboarding.xml b/packages/SystemUI/res/layout/recents_onboarding.xml
index adf1e74..2538612 100644
--- a/packages/SystemUI/res/layout/recents_onboarding.xml
+++ b/packages/SystemUI/res/layout/recents_onboarding.xml
@@ -37,7 +37,7 @@
             android:layout_height="wrap_content"
             android:layout_weight="1"
             android:layout_gravity="center_vertical"
-            android:textColor="@android:color/white"
+            android:textColor="?attr/wallpaperTextColor"
             android:textSize="16sp"/>
         <ImageView
             android:id="@+id/dismiss"
@@ -49,6 +49,7 @@
             android:layout_marginEnd="2dp"
             android:alpha="0.7"
             android:src="@drawable/ic_close_white"
+            android:tint="?attr/wallpaperTextColor"
             android:background="?android:attr/selectableItemBackgroundBorderless"
             android:contentDescription="@string/accessibility_desc_close"/>
     </LinearLayout>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 44691c2..157934f 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"maak kamera oop"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Kies nuwe taakuitleg"</string>
     <string name="cancel" msgid="6442560571259935130">"Kanselleer"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Hulpboodskapgebied"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Bevestig"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Raak die vingerafdruksensor"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Vingerafdrukikoon"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Programikoon"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Hulpboodskapgebied"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Soek tans vir jou …"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Gesig-ikoon"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Versoenbaarheid-zoem se knoppie."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoem kleiner na groter skerm."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth gekoppel."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Berging"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Wenke"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Kitsprogramme"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Kitsprogramme hoef nie geïnstalleer te word nie."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> loop tans"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Program is oopgemaak sonder dat dit geïnstalleer is."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Program is oopgemaak sonder dat dit geïnstalleer is. Tik om meer te wete te kom."</string>
     <string name="app_info" msgid="6856026610594615344">"Programinligting"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Gaan na blaaier"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Gaan na web"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Mobiele data"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi is af"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 966e4d7..492fa8c 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"ካሜራ ክፈት"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"የአዲስ ተግባር አቀማመጥን ይምረጡ"</string>
     <string name="cancel" msgid="6442560571259935130">"ይቅር"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"የእገዛ መልዕክት አካባቢ"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"አረጋግጥ"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"የጣት አሻራ ዳሳሹን ይንኩ"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"የጣት አሻራ አዶ"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"የመተግበሪያ አዶ"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"የእገዛ መልዕክት አካባቢ"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"እርስዎን በመፈለግ ላይ…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"የፊት አዶ"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"የተኳኋኝአጉላ አዝራር።"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"አነስተኛውን ማያ ወደ ትልቅ አጉላ።"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ብሉቱዝ ተያይዟል።"</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"ማከማቻ"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"ፍንጮች"</string>
     <string name="instant_apps" msgid="6647570248119804907">"የቅጽበት መተግበሪያዎች"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"ቅጽበታዊ መተግበሪያዎች መጫን አያስፈልጋቸውም።"</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> አሂድ"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"መተግበሪያ ሳይጫን ተከፍቷል።"</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"መተግበሪያ ሳይጫን ተከፍቷል። ተጨማሪ ለማወቅ መታ ያድርጉ።"</string>
     <string name="app_info" msgid="6856026610594615344">"የመተግበሪያ መረጃ"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"ወደ አሳሽ ሂድ"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"ወደ ድር ሂድ"</string>
     <string name="mobile_data" msgid="7094582042819250762">"የተንቀሳቃሽ ስልክ ውሂብ"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g>— <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi ጠፍቷል"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 278b00a..fe27bb7 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -107,10 +107,12 @@
     <string name="camera_label" msgid="7261107956054836961">"فتح الكاميرا"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"تحديد تنسيق جديد للمهمة"</string>
     <string name="cancel" msgid="6442560571259935130">"إلغاء"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"منطقة رسالة المساعدة"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"تأكيد"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"المس جهاز استشعار بصمات الإصبع"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"رمز بصمة الإصبع"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"رمز التطبيق"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"منطقة رسالة المساعدة"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"جارٍ البحث عن وجهك…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"رمز الوجه"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"زر تكبير/تصغير للتوافق."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"استخدام التكبير/التصغير لتحويل شاشة صغيرة إلى شاشة أكبر"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"تم توصيل البلوتوث."</string>
@@ -847,9 +849,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"سعة التخزين"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"تلميحات"</string>
     <string name="instant_apps" msgid="6647570248119804907">"التطبيقات الفورية"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"لا تتطلب التطبيقات الفورية إجراء التثبيت."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"التطبيق <xliff:g id="APP">%1$s</xliff:g> قيد التشغيل"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"تمّ فتح التطبيق بدون تثبيته."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"تمّ فتح التطبيق بدون تثبيته. انقر لمعرفة مزيد من المعلومات."</string>
     <string name="app_info" msgid="6856026610594615344">"معلومات عن التطبيق"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"الانتقال إلى المتصفح"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"الانتقال إلى الويب"</string>
     <string name="mobile_data" msgid="7094582042819250762">"بيانات الجوّال"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"‏تم إيقاف شبكة Wi-Fi"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 8912f15..8cde524 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"কেমেৰা খোলক"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"নতুন কাৰ্যৰ চানেকি বাছনি কৰক"</string>
     <string name="cancel" msgid="6442560571259935130">"বাতিল কৰক"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"সহায় বাৰ্তাৰ ক্ষেত্ৰ"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"নিশ্চিত কৰক"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"ফিংগাৰপ্ৰিণ্ট ছেন্সৰটো স্পৰ্শ কৰক"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"ফিংগাৰপ্ৰিণ্ট আইকন"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"এপ্লিকেশ্বন আইকন"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"সহায় বাৰ্তাৰ ক্ষেত্ৰ"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"আপোনাৰ মুখমণ্ডল বিচাৰি আছে…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"মুখমণ্ডলৰ আইকন"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"উপযোগিতা অনুসৰি জুম কৰা বুটাম।"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"স্ক্ৰীণৰ আকাৰ ডাঙৰ কৰিবলৈ জুম কৰক।"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ব্লুটুথ সংযোগ হ\'ল।"</string>
@@ -344,7 +346,7 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> সীমা"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> সকীয়নি"</string>
     <string name="quick_settings_work_mode_label" msgid="7608026833638817218">"কৰ্মস্থানৰ প্ৰ\'ফাইল"</string>
-    <string name="quick_settings_night_display_label" msgid="3577098011487644395">"ৰাতিৰ লাইট"</string>
+    <string name="quick_settings_night_display_label" msgid="3577098011487644395">"ৰাতিৰ পোহৰ"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"সূৰ্যাস্তত অন কৰক"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"সূৰ্যোদয়ৰ লৈকে"</string>
     <string name="quick_settings_night_secondary_label_on_at" msgid="6256314040368487637">"<xliff:g id="TIME">%s</xliff:g>ত অন কৰক"</string>
@@ -823,9 +825,14 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"সঞ্চয়াগাৰ"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"ইংগিতবোৰ"</string>
     <string name="instant_apps" msgid="6647570248119804907">"তাৎক্ষণিক এপসমূহ"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"তাৎক্ষণিক এপসমূহক ইনষ্টল কৰাৰ প্ৰয়োজন নাই।"</string>
+    <!-- no translation found for instant_apps_title (8738419517367449783) -->
+    <skip />
+    <!-- no translation found for instant_apps_message (1183313016396018086) -->
+    <skip />
+    <!-- no translation found for instant_apps_message_with_help (6179830437630729747) -->
+    <skip />
     <string name="app_info" msgid="6856026610594615344">"এপ্ সম্পৰ্কীয় তথ্য"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"ব্ৰাউজাৰলৈ যাওক"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"ৱেবলৈ যাওক"</string>
     <string name="mobile_data" msgid="7094582042819250762">"ম\'বাইল ডেটা"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"ৱাই-ফাই অফ অৱস্থাত আছে"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index f0779fb..2342a89 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"kemaranı açın"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Yeni tapşırıq sxemi seçin"</string>
     <string name="cancel" msgid="6442560571259935130">"Ləğv et"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Yardım mesajı bölməsi"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Təsdiq"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Barmaq izi sensoruna klikləyin"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Barmaq izi ikonası"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Tətbiq ikonası"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Yardım mesajı bölməsi"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Siz axtarılırsınız…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Üz işarəsi"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Uyğunluq zoom düyməsi."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Daha böyük ekranda uzaqlaşdır."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth qoşulub."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Yaddaş"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Məsləhətlər"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Ani Tətbiqlər"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Ani tətbiqlər quraşdırma tələb etmir."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> işləyir"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Quraşdırılmadan açılan tətbiq."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Quraşdırılmadan açılan tətbiq. Ətraflı məlumat üçün klikləyin."</string>
     <string name="app_info" msgid="6856026610594615344">"Tətbiq məlumatı"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Brauzerə daxil edin"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Vebə keçin"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Mobil data"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi deaktivdir"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 9dc6460..47422b2 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -104,10 +104,12 @@
     <string name="camera_label" msgid="7261107956054836961">"otvori kameru"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Izaberi novi raspored zadataka"</string>
     <string name="cancel" msgid="6442560571259935130">"Otkaži"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Oblast poruke za pomoć"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Potvrdi"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Dodirnite senzor za otisak prsta"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikona otiska prsta"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Ikona aplikacije"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Oblast poruke za pomoć"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Tražimo vas…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ikona lica"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Dugme Zum kompatibilnosti."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zumiranje sa manjeg na veći ekran."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth je priključen."</string>
@@ -829,9 +831,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Memorijski prostor"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Saveti"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Instant aplikacije"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Instant aplikacije ne zahtevaju instalaciju."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> je pokrenuta"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Aplikacija se otvorila bez instaliranja."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Aplikacija se otvorila bez instaliranja. Dodirnite da biste saznali više."</string>
     <string name="app_info" msgid="6856026610594615344">"Informacije o aplikaciji"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Idi na pregledač"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Idi na veb"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Mobilni podaci"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi je isključen"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 9898dbd..de01516 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -105,10 +105,12 @@
     <string name="camera_label" msgid="7261107956054836961">"адкрыць камеру"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Выберыце новы макет заданняў"</string>
     <string name="cancel" msgid="6442560571259935130">"Скасаваць"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Поле даведачнага паведамлення"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Пацвердзіць"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Дакраніцеся да сканера адбіткаў пальцаў"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Значок адбіткаў пальцаў"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Значок праграмы"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Вобласць даведачнага паведамлення"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Ідзе пошук вашага твару…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Значок твару"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Кнопка сумяшчальнасці маштаба."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Маштабаванне малых элементаў для большага экрана."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth-сувязь."</string>
@@ -837,9 +839,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Захоўванне"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Падказкі"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Імгненныя праграмы"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Імгненныя праграмы не патрабуюць усталёўкі."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"Праграма \"<xliff:g id="APP">%1$s</xliff:g>\" запушчана"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Праграма адкрыта без усталёўкі."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Праграма адкрыта без усталёўкі. Націсніце, каб даведацца больш."</string>
     <string name="app_info" msgid="6856026610594615344">"Інфармацыя пра праграму"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Перайсці ў браўзер"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Перайсці ў інтэрнэт"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Маб. перадача даных"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi выключаны"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index a5506a3..29d89ec 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"отваряне на камерата"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Избиране на ново оформление за задачите"</string>
     <string name="cancel" msgid="6442560571259935130">"Отказ"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Област за помощно съобщение"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Потвърждаване"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Докоснете сензора за отпечатъци"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Икона за отпечатък"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Икона на приложението"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Област за помощно съобщение"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Търсим ви…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Икона на лице"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Бутон за промяна на мащаба с цел съвместимост."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Промяна на мащаба на екрана от по-малък до по-голям."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth е включен."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Хранилище"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Съвети"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Мигновени приложения"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"За мигновените приложения не се изисква инсталиране."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> работи"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Приложението се отвори, без да бъде инсталирано."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Приложението се отвори, без да бъде инсталирано. Докоснете, за да научите повече."</string>
     <string name="app_info" msgid="6856026610594615344">"Информация за приложението"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Към браузъра"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Към мрежата"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Мобилни данни"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Функцията за Wi‑Fi е изключена"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 5d52103..d2f6401 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -31,7 +31,7 @@
     </plurals>
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"কোনো বিজ্ঞপ্তি নেই"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"চলতে-থাকা"</string>
-    <string name="status_bar_latest_events_title" msgid="6594767438577593172">"বিজ্ঞপ্তিগুলি"</string>
+    <string name="status_bar_latest_events_title" msgid="6594767438577593172">"বিজ্ঞপ্তি"</string>
     <string name="battery_low_title" msgid="9187898087363540349">"চার্জ শীঘ্রই শেষ হয়ে যেতে পারে"</string>
     <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> অবশিষ্ট আছে"</string>
     <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> বাকি আছে, বর্তমান ব্যবহারের ভিত্তিতে আর <xliff:g id="TIME">%2$s</xliff:g> চলবে"</string>
@@ -49,7 +49,7 @@
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"অটো-রোটেট স্ক্রিন"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"মিউট করুন"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"স্বতঃ"</string>
-    <string name="status_bar_settings_notifications" msgid="397146176280905137">"বিজ্ঞপ্তিগুলি"</string>
+    <string name="status_bar_settings_notifications" msgid="397146176280905137">"বিজ্ঞপ্তি"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"ব্লুটুথ টিথার করা হয়েছে"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"ইনপুট পদ্ধতিগুলি সেট আপ করুন"</string>
     <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"ফিজিক্যাল কীবোর্ড"</string>
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"ক্যামেরা খুলুন"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"নতুন কার্য লেআউট বেছে নিন"</string>
     <string name="cancel" msgid="6442560571259935130">"বাতিল করুন"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"সহায়তার মেসেজ দেখানোর জায়গা"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"কনফার্ম করুন"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"আঙ্গুলের ছাপের সেন্সর স্পর্শ করুন"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"আঙ্গুলের ছাপের আইকন"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"অ্যাপ্লিকেশনের আইকন"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"সহায়তার মেসেজ দেখানোর জায়গা"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"আপনার জন্য খোঁজা হচ্ছে…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"ফেস আইকন"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"সামঞ্জস্যের জুম বোতাম৷"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ছোট থেকে বৃহৎ স্ক্রীণে জুম করুন৷"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ব্লুটুথ সংযুক্ত হয়েছে৷"</string>
@@ -174,7 +176,7 @@
     <string name="accessibility_battery_level" msgid="7451474187113371965">"<xliff:g id="NUMBER">%d</xliff:g> শতাংশ ব্যাটারি রয়েছে৷"</string>
     <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"ব্যাটারি চার্জ হচ্ছে, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> শতাংশ৷"</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"সিস্টেম সেটিংস৷"</string>
-    <string name="accessibility_notifications_button" msgid="4498000369779421892">"বিজ্ঞপ্তিগুলি৷"</string>
+    <string name="accessibility_notifications_button" msgid="4498000369779421892">"বিজ্ঞপ্তি৷"</string>
     <string name="accessibility_overflow_action" msgid="5681882033274783311">"সমস্ত বিজ্ঞপ্তি দেখুন"</string>
     <string name="accessibility_remove_notification" msgid="3603099514902182350">"বিজ্ঞপ্তি সাফ করুন৷"</string>
     <string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS সক্ষম করা হয়েছে৷"</string>
@@ -334,7 +336,7 @@
       <item quantity="one">%dটি ডিভাইস</item>
       <item quantity="other">%dটি ডিভাইস</item>
     </plurals>
-    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"বিজ্ঞপ্তিগুলি"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"বিজ্ঞপ্তি"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"ফ্ল্যাশলাইট"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"মোবাইল ডেটা"</string>
     <string name="quick_settings_cellular_detail_data_usage" msgid="1964260360259312002">"ডেটার ব্যবহার"</string>
@@ -576,7 +578,7 @@
     <string name="broadcast_tile" msgid="3894036511763289383">"সম্প্রচার টাইল"</string>
     <string name="zen_alarm_warning_indef" msgid="3482966345578319605">"তার আগে আপনি এটিকে বন্ধ না করা পর্যন্ত আপনি পরবর্তী <xliff:g id="WHEN">%1$s</xliff:g> অ্যালার্ম শুনতে পাবেন না"</string>
     <string name="zen_alarm_warning" msgid="444533119582244293">"আপনি আপনার পরবর্তী <xliff:g id="WHEN">%1$s</xliff:g> অ্যালার্ম শুনতে পাবেন না"</string>
-    <string name="alarm_template" msgid="3980063409350522735">"<xliff:g id="WHEN">%1$s</xliff:g> -টায়"</string>
+    <string name="alarm_template" msgid="3980063409350522735">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
     <string name="alarm_template_far" msgid="4242179982586714810">"<xliff:g id="WHEN">%1$s</xliff:g> -তে"</string>
     <string name="accessibility_quick_settings_detail" msgid="2579369091672902101">"দ্রুত সেটিংস, <xliff:g id="TITLE">%s</xliff:g>৷"</string>
     <string name="accessibility_status_bar_hotspot" msgid="4099381329956402865">"হটস্পট"</string>
@@ -679,7 +681,7 @@
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"হোম"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"সাম্প্রতিকগুলি"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"পিছনে"</string>
-    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"বিজ্ঞপ্তিগুলি"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"বিজ্ঞপ্তি"</string>
     <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"কীবোর্ড শর্টকাট"</string>
     <string name="keyboard_shortcut_group_system_switch_input" msgid="8413348767825486492">"কীবোর্ড লে-আউট পাল্টান"</string>
     <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"অ্যাপ্লিকেশানগুলি"</string>
@@ -823,9 +825,14 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"স্টোরেজ"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"হিন্ট"</string>
     <string name="instant_apps" msgid="6647570248119804907">"ঝটপট অ্যাপ"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"ঝটপট অ্যাপ ইনস্টল করার প্রয়োজন হয় না।"</string>
+    <!-- no translation found for instant_apps_title (8738419517367449783) -->
+    <skip />
+    <!-- no translation found for instant_apps_message (1183313016396018086) -->
+    <skip />
+    <!-- no translation found for instant_apps_message_with_help (6179830437630729747) -->
+    <skip />
     <string name="app_info" msgid="6856026610594615344">"অ্যাপের তথ্য"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"ব্রাউজারে যান"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"ওয়েবে যান"</string>
     <string name="mobile_data" msgid="7094582042819250762">"মোবাইল ডেটা"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"ওয়াই ফাই বন্ধ আছে"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 4527e9a..ac0c05e 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -104,10 +104,12 @@
     <string name="camera_label" msgid="7261107956054836961">"otvori kameru"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Odaberite novi raspored zadataka"</string>
     <string name="cancel" msgid="6442560571259935130">"Otkaži"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Prostor za poruku za pomoć"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Potvrdite"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Dodirnite senzor za otisak prsta"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikona za otisak prsta"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Ikona aplikacije"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Prostor za poruku za pomoć"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Tražimo vas…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ikona lica"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Dugme za uvećavanje u slučaju nekompatibilnosti."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Uvećani prikaz manjeg ekrana na većem ekranu."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth je povezan."</string>
@@ -831,9 +833,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Pohrana"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Savjeti"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Instant-aplikacije"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Za instant aplikacije nije potrebna instalacija"</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"Pokrenuta je aplikacija <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Aplikacija je otvorena bez prethodne instalacije."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Aplikacija je otvorena bez prethodne instalacije. Dodirnite da saznate više."</string>
     <string name="app_info" msgid="6856026610594615344">"Informacije o aplikaciji"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Idi na preglednik"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Idite na internet"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Prijenos podataka"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"WiFi veza je isključena"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 23754ea..b4a2f3b 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"obre la càmera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Selecciona el disseny de la tasca nova"</string>
     <string name="cancel" msgid="6442560571259935130">"Cancel·la"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Àrea de missatge d\'ajuda"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirma"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Toca el sensor d\'empremtes digitals"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Icona d\'empremta digital"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Icona d\'aplicació"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Àrea de missatge d\'ajuda"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"S\'està cercant la teva cara…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Icona facial"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botó de zoom de compatibilitat."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Amplia menys com més gran sigui la pantalla."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connectat."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Emmagatzematge"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Suggeriments"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Aplicacions instantànies"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"No cal instal·lar les aplicacions instantànies."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"S\'està executant <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"L\'aplicació s\'ha obert sense instal·lar-se."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"L\'aplicació s\'ha obert sense instal·lar-se. Toca per obtenir més informació."</string>
     <string name="app_info" msgid="6856026610594615344">"Informació de l\'aplicació"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Ves al navegador"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Ves al web"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Dades mòbils"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> - <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"La Wi-Fi està desactivada"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index e7583b5..6d4af4a 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -105,10 +105,12 @@
     <string name="camera_label" msgid="7261107956054836961">"spustit fotoaparát"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Vybrat nové rozvržení úkolů"</string>
     <string name="cancel" msgid="6442560571259935130">"Zrušit"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Oblast pro zprávu nápovědy"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Potvrdit"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Dotkněte se snímače otisků prstů"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikona otisku prstu"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Ikona aplikace"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Oblast pro zprávu nápovědy"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Hledáme vás…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ikona obličeje"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Tlačítko úpravy velikosti z důvodu kompatibility"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zvětšit menší obrázek na větší obrazovku."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Rozhraní Bluetooth je připojeno."</string>
@@ -837,9 +839,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Úložiště"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Tipy"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Okamžité aplikace"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Okamžité aplikace není třeba instalovat."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"Aplikace <xliff:g id="APP">%1$s</xliff:g> je spuštěna"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Aplikace byla otevřena bez instalace."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Aplikace byla otevřena bez instalace. Klepnutím zobrazíte další informace."</string>
     <string name="app_info" msgid="6856026610594615344">"O aplikaci"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Přejít do prohlížeče"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Přejít na web"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Mobilní data"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi je vypnuta"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 31634a9..ade7db1 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"åbn kamera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Vælg nyt opgavelayout"</string>
     <string name="cancel" msgid="6442560571259935130">"Annuller"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Område med hjælpemeddelelse"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Bekræft"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Sæt fingeren på fingeraftrykslæseren"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikon for fingeraftryk"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Appens ikon"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Område med hjælpemeddelelse"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Forsøger at finde dig…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ansigt"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Knap for kompatibilitetszoom."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom mindre til større skærm."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth tilsluttet."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Lagerplads"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Tips"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Instant apps kræver ingen installation."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> kører"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"En app blev åbnet uden at blive installeret."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"En app blev åbnet uden at blive installeret. Tryk for at få flere oplysninger."</string>
     <string name="app_info" msgid="6856026610594615344">"Appinfo"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Gå til en browser"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Gå til website"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Mobildata"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi er slået fra"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index aa6e449..06aac5c 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"Kamera öffnen"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Neues Aufgabenlayout auswählen"</string>
     <string name="cancel" msgid="6442560571259935130">"Abbrechen"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Bereich für die Hilfemeldung"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Bestätigen"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Berühre den Fingerabdrucksensor"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Fingerabdruck-Symbol"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"App-Symbol"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Bereich für die Hilfemeldung"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Wir suchen nach dir…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Gesichtssymbol"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Schaltfläche für Kompatibilitätszoom"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom auf einen größeren Bildschirm"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Mit Bluetooth verbunden"</string>
@@ -448,9 +450,9 @@
     <string name="dnd_suppressing_shade_text" msgid="1904574852846769301">"Benachrichtigungen durch \"Bitte nicht stören\" pausiert"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Jetzt starten"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"Keine Benachrichtigungen"</string>
-    <string name="profile_owned_footer" msgid="8021888108553696069">"Profil wird möglicherweise überwacht."</string>
-    <string name="vpn_footer" msgid="2388611096129106812">"Das Netzwerk wird möglicherweise überwacht."</string>
-    <string name="branded_vpn_footer" msgid="2168111859226496230">"Das Netzwerk wird möglicherweise überwacht"</string>
+    <string name="profile_owned_footer" msgid="8021888108553696069">"Profil wird eventuell überwacht."</string>
+    <string name="vpn_footer" msgid="2388611096129106812">"Das Netzwerk wird eventuell überwacht."</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Das Netzwerk wird eventuell überwacht"</string>
     <string name="quick_settings_disclosure_management_monitoring" msgid="6645176135063957394">"Deine Organisation verwaltet dieses Gerät und kann den Netzwerkverkehr überwachen"</string>
     <string name="quick_settings_disclosure_named_management_monitoring" msgid="370622174777570853">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> verwaltet dieses Gerät und kann den Netzwerkverkehr überwachen"</string>
     <string name="quick_settings_disclosure_management_named_vpn" msgid="1085137869053332307">"Das Gerät wird von deiner Organisation verwaltet und ist mit <xliff:g id="VPN_APP">%1$s</xliff:g> verbunden"</string>
@@ -461,7 +463,7 @@
     <string name="quick_settings_disclosure_named_management_vpns" msgid="7777821385318891527">"Das Gerät wird von <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> verwaltet und ist mit VPNs verbunden"</string>
     <string name="quick_settings_disclosure_managed_profile_monitoring" msgid="5125463987558278215">"Deine Organisation kann den Netzwerkverkehr in deinem Arbeitsprofil überwachen"</string>
     <string name="quick_settings_disclosure_named_managed_profile_monitoring" msgid="8973606847896650284">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> kann den Netzwerkverkehr in deinem Arbeitsprofil überwachen"</string>
-    <string name="quick_settings_disclosure_monitoring" msgid="679658227269205728">"Das Netzwerk wird möglicherweise überwacht"</string>
+    <string name="quick_settings_disclosure_monitoring" msgid="679658227269205728">"Das Netzwerk wird eventuell überwacht"</string>
     <string name="quick_settings_disclosure_vpns" msgid="8170318392053156330">"Das Gerät ist mit VPNs verbunden"</string>
     <string name="quick_settings_disclosure_managed_profile_named_vpn" msgid="3494535754792751741">"Arbeitsprofil verbunden mit <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
     <string name="quick_settings_disclosure_personal_profile_named_vpn" msgid="4467456202486569906">"Das persönliche Profil ist mit <xliff:g id="VPN_APP">%1$s</xliff:g> verbunden"</string>
@@ -827,9 +829,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Speicher"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Hinweise"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Instant-Apps"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Bei Instant-Apps ist keine vorherige Installation erforderlich."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> wird ausgeführt"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"App wurde geöffnet, ohne vorher installiert zu werden."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"App wurde geöffnet, ohne vorher installiert zu werden. Tippe, um weitere Informationen zu erhalten."</string>
     <string name="app_info" msgid="6856026610594615344">"App-Informationen"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Browser öffnen"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Web aufrufen"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Mobile Daten"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"WLAN ist deaktiviert"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 1a1c762..1892da6 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"άνοιγμα φωτογραφικής μηχανής"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Επιλέξτε τη νέα διάταξη εργασίας"</string>
     <string name="cancel" msgid="6442560571259935130">"Ακύρωση"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Περιοχή μηνυμάτων βοήθειας"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Επιβεβαίωση"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Αγγίξτε τον αισθητήρα δακτυλικών αποτυπωμάτων"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Εικονίδιο δακτυλικών αποτυπωμάτων"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Εικονίδιο εφαρμογής"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Περιοχή μηνυμάτων βοήθειας"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Αναζήτηση για εσάς…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Εικονίδιο προσώπου"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Κουμπί εστίασης συμβατότητας."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Ζουμ από μικρότερη σε μεγαλύτερη οθόνη."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Το Bluetooth είναι συνδεδεμένο."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Αποθηκευτικός χώρος"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Συμβουλές"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Instant Εφαρμογές"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Οι Instant Εφαρμογές δεν απαιτούν εγκατάσταση."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"Η εφαρμογή <xliff:g id="APP">%1$s</xliff:g> εκτελείται"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Η εφαρμογή άνοιξε χωρίς να έχει εγκατασταθεί."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Η εφαρμογή άνοιξε χωρίς να έχει εγκατασταθεί. Πατήστε για να μάθετε περισσότερα."</string>
     <string name="app_info" msgid="6856026610594615344">"Πληροφορίες εφαρμογής"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Μετάβ. σε πρόγ. περ."</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Μετάβαση στον ιστό"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Δεδομένα κινητής τηλεφωνίας"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> - <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Το Wi-Fi είναι ανενεργό"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index c0afae6..6503470 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"open camera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Select new task layout"</string>
     <string name="cancel" msgid="6442560571259935130">"Cancel"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Help message area"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirm"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Touch the fingerprint sensor"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Fingerprint icon"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Application icon"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Help message area"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Looking for you…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Face icon"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Compatibility zoom button."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom smaller to larger screen."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connected."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Storage"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Hints"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Instant apps don\'t require installation."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> running"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"App opened without being installed."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"App opened without being installed. Tap to find out more."</string>
     <string name="app_info" msgid="6856026610594615344">"App info"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Go to browser"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Go to web"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Mobile data"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi is off"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 488c748..9e4081c 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"open camera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Select new task layout"</string>
     <string name="cancel" msgid="6442560571259935130">"Cancel"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Help message area"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirm"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Touch the fingerprint sensor"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Fingerprint icon"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Application icon"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Help message area"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Looking for you…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Face icon"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Compatibility zoom button."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom smaller to larger screen."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connected."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Storage"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Hints"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Instant apps don\'t require installation."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> running"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"App opened without being installed."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"App opened without being installed. Tap to find out more."</string>
     <string name="app_info" msgid="6856026610594615344">"App info"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Go to browser"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Go to web"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Mobile data"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi is off"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index c0afae6..6503470 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"open camera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Select new task layout"</string>
     <string name="cancel" msgid="6442560571259935130">"Cancel"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Help message area"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirm"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Touch the fingerprint sensor"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Fingerprint icon"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Application icon"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Help message area"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Looking for you…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Face icon"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Compatibility zoom button."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom smaller to larger screen."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connected."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Storage"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Hints"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Instant apps don\'t require installation."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> running"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"App opened without being installed."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"App opened without being installed. Tap to find out more."</string>
     <string name="app_info" msgid="6856026610594615344">"App info"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Go to browser"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Go to web"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Mobile data"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi is off"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index c0afae6..6503470 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"open camera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Select new task layout"</string>
     <string name="cancel" msgid="6442560571259935130">"Cancel"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Help message area"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirm"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Touch the fingerprint sensor"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Fingerprint icon"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Application icon"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Help message area"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Looking for you…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Face icon"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Compatibility zoom button."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom smaller to larger screen."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connected."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Storage"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Hints"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Instant apps don\'t require installation."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> running"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"App opened without being installed."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"App opened without being installed. Tap to find out more."</string>
     <string name="app_info" msgid="6856026610594615344">"App info"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Go to browser"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Go to web"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Mobile data"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi is off"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index f775bb1..40205b9 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎‎‎‏‎‎‏‎‏‎‎‎‏‏‎‎‏‏‎‏‏‏‎‎‎‎‏‏‎‎‎‏‏‎‏‎‎‏‎‏‎‎‎‏‏‎‏‏‏‎‎‎‎‏‎open camera‎‏‎‎‏‎"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‏‏‏‏‎‎‎‏‏‎‎‎‎‎‏‏‏‎‏‎‎‎‎‏‎‏‏‏‎‎‏‎‎‎‏‎‏‎‎‏‎‎‏‎‎‏‏‏‏‎‎‎‎Select new task layout‎‏‎‎‏‎"</string>
     <string name="cancel" msgid="6442560571259935130">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‏‎‎‎‏‎‎‏‎‎‏‎‏‎‏‏‎‏‎‎‏‎‎‏‎‏‎‏‏‏‏‎‎‎‏‎‏‏‎‏‏‎‎‏‏‎‎‏‏‎‏‎‎Cancel‎‏‎‎‏‎"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‎‏‎‎‎‏‏‏‏‎‏‏‏‏‎‏‎‎‎‎‏‎‎‎‎‏‏‏‎‎‎‎‎‎‎‏‏‎‎‎‏‎‎‏‏‎‏‏‏‏‏‎Help message area‎‏‎‎‏‎"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‎‎‎‏‎‎‏‎‎‏‎‎‏‏‏‎‏‏‎‎‎‎‎‏‎‎‎‎‏‎‎‎‎‎‎‎‎‎‎‎‏‏‏‎‎‎‎‎‏‎‎‎‏‎‎Confirm‎‏‎‎‏‎"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‎‏‎‎‏‏‏‏‏‏‎‎‏‏‏‎‏‎‎‏‏‏‎‎‏‎‎‎‏‏‏‎‏‏‏‎‎‎‎‎‏‎Touch the fingerprint sensor‎‏‎‎‏‎"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‎‏‏‏‏‎‏‎‏‎‏‎‏‎‎‏‎‏‏‎‏‎‎‎‎‏‏‎‏‎‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‏‎‏‎‏‎‎Fingerprint icon‎‏‎‎‏‎"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‏‏‎‎‏‏‎‎‎‏‎‏‏‎‎‎‏‎‏‎‏‏‏‏‎‏‎‏‎‎‎‏‏‎‎‏‎‏‏‏‎‎‎‎‎‎‎‎‎‏‎‏‎‎‎‏‎Application icon‎‏‎‎‏‎"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‎‎‎‎‏‏‎‏‎‏‏‏‎‎‏‏‎‎‎‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‎‎‎‎‏‏‎‎‎‏‎‎‎‏‏‏‎Help message area‎‏‎‎‏‎"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‏‎‏‎‎‎‎‎‎‏‏‏‏‎‏‏‎‏‎‏‎‎‏‎‏‎‎‏‎‏‏‏‏‎‏‏‎‎‏‎‏‎‏‏‎‏‏‏‎‎‎‎‏‎Looking for you…‎‏‎‎‏‎"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‎‎‎‏‏‏‎‎‎‏‎‎‏‎‎‏‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‏‏‎‎‎‏‎‎‏‏‎‎‎‎‎‏‎‎Face icon‎‏‎‎‏‎"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‎‏‏‏‏‏‎‏‎‏‏‏‎‎‎‏‏‎‏‏‎‏‏‎‎‎‏‎‏‎‎‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‏‎‏‏‎Compatibility zoom button.‎‏‎‎‏‎"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‎‏‎‎‏‎‏‏‏‎‎‏‎‎‏‎‏‏‏‎‏‏‎‏‏‏‎‏‎‎‏‎‎‎‏‏‎‎‎‏‎‎‏‏‏‏‎‏‏‏‎‏‎‎‎Zoom smaller to larger screen.‎‏‎‎‏‎"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‏‎‎‎‏‎‏‎‎‏‎‏‏‎‏‎‎‏‎‏‎‎‎‏‏‏‏‎‎‏‎‎‏‏‏‎‏‎‏‎‎‏‎‏‏‏‏‎‎‏‎‏‎‎Bluetooth connected.‎‏‎‎‏‎"</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‏‎‏‏‎‏‎‎‎‏‏‎‏‏‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‏‎‏‎‎‎‎‏‏‎‎‎‎‎‏‏‏‎‎‎‏‎‎‎‏‎Storage‎‏‎‎‏‎"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‎‎‎‏‏‏‎‎‏‏‏‎‏‎‎‏‎‎‏‏‏‏‎‎‏‏‏‎‎‎‏‏‏‏‎‏‏‎‎‎‎‏‎‎‎‏‎‏‏‎‎‎‏‎Hints‎‏‎‎‏‎"</string>
     <string name="instant_apps" msgid="6647570248119804907">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‎‎‎‎‏‏‏‎‏‎‎‏‏‏‏‎‏‎‏‏‏‎‎‏‏‎‏‎‏‎‏‎‎‎‏‎‏‏‏‎‎‎‏‏‏‏‏‎‏‎‏‏‎Instant Apps‎‏‎‎‏‎"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‎‎‏‎‎‏‎‏‏‏‎‏‏‎‏‏‎‎‎‏‏‎‏‏‎‎‎‏‎‎‎‏‎‎‎Instant apps don\'t require installation.‎‏‎‎‏‎"</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‏‎‏‎‎‎‏‏‎‏‎‎‏‎‎‎‎‎‎‏‎‏‏‏‏‏‏‎‎‎‎‎‏‏‎‏‏‏‏‏‎‎‎‏‎‏‏‎‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎ running‎‏‎‎‏‎"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‏‏‎‏‎‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‎‏‏‎‏‎‎‎‎‎‎‎‏‏‎‎‎‎‏‎‏‏‏‎‎‎‏‏‎‏‎‎‏‏‎‎App opened without being installed.‎‏‎‎‏‎"</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‎‎‎‏‏‎‎‏‎‏‎‏‏‎‎‎‎‏‎‏‎‎‏‏‏‎‏‏‏‎‎‏‎‎‎‎‎‎‏‎‏‏‏‏‎‎‎‎‏‎‎‏‏‎App opened without being installed. Tap to learn more.‎‏‎‎‏‎"</string>
     <string name="app_info" msgid="6856026610594615344">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‎‎‏‎‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‏‎‎‏‏‏‎‎‎‏‏‏‏‎‎‎‎‏‎‎‎‎‎‎‏‏‎‎‎‎‎App info‎‏‎‎‏‎"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‏‎‎‏‎‎‎‏‎‎‎‏‏‎‎‎‎‏‏‏‎‏‏‎‎‎‏‎‏‏‏‎‎‏‎‎‎‎‏‎‏‏‏‎‏‏‎‏‎‏‏‏‎Go to browser‎‏‎‎‏‎"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎‏‎‏‏‎‎‏‎‏‏‎‎‎‎‏‏‏‎‎‏‏‏‎‏‎‎‏‏‎‎‏‎‏‎‏‎‏‏‏‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎Go to web‎‏‎‎‏‎"</string>
     <string name="mobile_data" msgid="7094582042819250762">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‏‎‏‎‏‎‎‎‎‎‏‎‎‏‏‎‎‎‏‏‏‎‏‏‏‏‏‎‎‎‎‎‏‏‎‏‏‎‏‎‎‏‎‏‎‎‏‎‎‏‎‏‎‎Mobile data‎‏‎‎‏‎"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‎‎‎‏‎‏‏‎‏‏‎‎‏‏‏‏‏‎‎‏‏‎‎‏‏‏‏‏‎‎‎‎‎‏‏‏‎‎‏‎‎‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="ID_1">%1$s</xliff:g>‎‏‎‎‏‏‏‎ — ‎‏‎‎‏‏‎<xliff:g id="ID_2">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‎‎‏‏‏‏‏‎‎‎‎‎‎‎‎‎‎‏‏‎‏‎‏‎‏‏‏‏‎‎‏‎‏‎‎‏‏‎‎‏‎‎‎‏‎‎‏‏‏‏‎‏‎Wi-Fi is off‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 31509dc..d4adfdc 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"abrir cámara"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Selecciona el nuevo diseño de la tarea."</string>
     <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Área de mensajes de ayuda"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirmar"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Toca el sensor de huellas digitales"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ícono de huella digital"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Ícono de la aplicación"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Área de mensajes de ayuda"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Autenticando tu rostro…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ícono de rostro"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botón de zoom de compatibilidad"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de pantalla más pequeña a más grande"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth conectado"</string>
@@ -825,9 +827,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Almacenamiento"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Sugerencias"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Apps instantáneas"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Las Apps instantáneas no requieren instalación."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> en ejecución"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"La app se abrió sin instalarse."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"La app se abrió sin instalarse. Presiona para obtener más información."</string>
     <string name="app_info" msgid="6856026610594615344">"Información de apps"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Ir al navegador"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Ir a la Web"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Datos móviles"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi desactivado"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 2cc3abd..00c179c 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -19,7 +19,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="7164937344850004466">"IU del sistema"</string>
+    <string name="app_label" msgid="7164937344850004466">"UI del sistema"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Borrar"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Quitar de la lista"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Información de la aplicación"</string>
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"abrir cámara"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Seleccionar diseño de tarea nueva"</string>
     <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Área de mensaje de ayuda"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirmar"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Toca el sensor de huellas digitales"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Icono de huella digital"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Icono de aplicación"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Área de mensaje de ayuda"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Buscando tu cara…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Icono de cara"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botón de zoom de compatibilidad"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de pantalla más pequeña a más grande"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth conectado"</string>
@@ -561,13 +563,13 @@
     <string name="output_service_bt" msgid="6224213415445509542">"Bluetooth"</string>
     <string name="output_service_wifi" msgid="3749735218931825054">"Wi‑Fi"</string>
     <string name="output_service_bt_wifi" msgid="4486837869988770896">"Bluetooth y Wi‑Fi"</string>
-    <string name="system_ui_tuner" msgid="708224127392452018">"Configurador de IU del sistema"</string>
+    <string name="system_ui_tuner" msgid="708224127392452018">"Configurador de UI del sistema"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Mostrar porcentaje de batería insertado"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Mostrar el porcentaje del nivel de batería en el icono de la barra de estado cuando no se esté cargando"</string>
     <string name="quick_settings" msgid="10042998191725428">"Ajustes rápidos"</string>
     <string name="status_bar" msgid="4877645476959324760">"Barra de estado"</string>
     <string name="overview" msgid="4018602013895926956">"Aplicaciones recientes"</string>
-    <string name="demo_mode" msgid="2532177350215638026">"Modo de demostración de IU del sistema"</string>
+    <string name="demo_mode" msgid="2532177350215638026">"Modo de demostración de UI del sistema"</string>
     <string name="enable_demo_mode" msgid="4844205668718636518">"Habilitar modo de demostración"</string>
     <string name="show_demo_mode" msgid="2018336697782464029">"Mostrar modo de demostración"</string>
     <string name="status_bar_ethernet" msgid="5044290963549500128">"Ethernet"</string>
@@ -584,12 +586,12 @@
     <string name="accessibility_status_bar_hotspot" msgid="4099381329956402865">"Zona Wi-Fi"</string>
     <string name="accessibility_managed_profile" msgid="6613641363112584120">"Perfil de trabajo"</string>
     <string name="tuner_warning_title" msgid="7094689930793031682">"Diversión solo para algunos"</string>
-    <string name="tuner_warning" msgid="8730648121973575701">"El configurador de IU del sistema te ofrece otras formas de modificar y personalizar la interfaz de usuario de Android. Estas funciones experimentales pueden cambiar, fallar o desaparecer en futuras versiones. Te recomendamos que tengas cuidado."</string>
+    <string name="tuner_warning" msgid="8730648121973575701">"El configurador de UI del sistema te ofrece otras formas de modificar y personalizar la interfaz de usuario de Android. Estas funciones experimentales pueden cambiar, fallar o desaparecer en futuras versiones. Te recomendamos que tengas cuidado."</string>
     <string name="tuner_persistent_warning" msgid="8597333795565621795">"Estas funciones experimentales pueden cambiar, fallar o desaparecer en futuras versiones. Te recomendamos que tengas cuidado."</string>
     <string name="got_it" msgid="2239653834387972602">"Entendido"</string>
-    <string name="tuner_toast" msgid="603429811084428439">"¡Enhorabuena! El configurador de IU del sistema se ha añadido a Ajustes"</string>
+    <string name="tuner_toast" msgid="603429811084428439">"¡Enhorabuena! El configurador de UI del sistema se ha añadido a Ajustes"</string>
     <string name="remove_from_settings" msgid="8389591916603406378">"Quitar de Ajustes"</string>
-    <string name="remove_from_settings_prompt" msgid="6069085993355887748">"¿Quitar el configurador de IU del sistema de Ajustes y dejar de utilizar sus funciones?"</string>
+    <string name="remove_from_settings_prompt" msgid="6069085993355887748">"¿Quitar el configurador de UI del sistema de Ajustes y dejar de utilizar sus funciones?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"La aplicación no está instalada en tu dispositivo"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Mostrar los segundos del reloj"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Muestra los segundos del reloj en la barra de estado. Puede afectar a la duración de la batería."</string>
@@ -825,9 +827,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Almacenamiento"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Sugerencias"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Aplicaciones Instantáneas"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"No es necesario instalar las Aplicaciones Instantáneas."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> se está ejecutando"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"La aplicación se abre sin necesidad de instalarla."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"La aplicación se abre sin necesidad de instalarla. Toca para obtener más información."</string>
     <string name="app_info" msgid="6856026610594615344">"Información de la aplicación"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Ir al navegador"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Ir a la Web"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Datos móviles"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> ‑ <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi desactivado"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index f22dc1a..246f1f8 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"ava kaamera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Uue toimingu paigutuse valimine"</string>
     <string name="cancel" msgid="6442560571259935130">"Tühista"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Abisõnumi ala"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Kinnita"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Puudutage sõrmejäljeandurit"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Sõrmejälje ikoon"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Rakenduse ikoon"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Abisõnumi ala"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Otsitakse teid …"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Näoikoon"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Sobivussuumi nupp."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Suumi suuremale ekraanile vähem."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth on ühendatud."</string>
@@ -825,9 +827,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Salvestusruum"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Vihjed"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Installimata avatavad rakendused"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Installimata avatavaid rakendusi pole vaja installida."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"Rakendus <xliff:g id="APP">%1$s</xliff:g> töötab"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Rakendus avati installimata."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Rakendus avati installimata. Lisateabe saamiseks puudutage."</string>
     <string name="app_info" msgid="6856026610594615344">"Rakenduse teave"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Ava brauser"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Avage veebis"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Mobiilne andmeside"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"WiFi on välja lülitatud"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 87dba92..b73946e 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"ireki kamera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Hautatu zereginen diseinua"</string>
     <string name="cancel" msgid="6442560571259935130">"Utzi"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Laguntza-mezuaren eremua"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Berretsi"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Sakatu hatz-marken sentsorea"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Hatz-markaren ikonoa"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Aplikazioaren ikonoa"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Laguntza-mezuaren eremua"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Zure bila…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Aurpegiaren ikonoa"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Zoom-bateragarritasunaren botoia."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Handiagotu pantaila txikia."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetootha konektatuta."</string>
@@ -825,9 +827,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Memoria"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Aholkuak"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Zuzeneko aplikazioak"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Zuzeneko aplikazioak ez dira instalatu behar."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> exekutatzen ari da"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Ezer instalatu gabe ireki da aplikazioa."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Ezer instalatu gabe ireki da aplikazioa. Sakatu informazio gehiago lortzeko."</string>
     <string name="app_info" msgid="6856026610594615344">"Aplikazioari buruzko informazioa"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Joan arakatzailera"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Joan sarera"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Datu-konexioa"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> - <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi konexioa desaktibatuta dago"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 5411d3d..3997f1a 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -47,7 +47,7 @@
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"تنظیمات"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"چرخش خودکار صفحه"</string>
-    <string name="status_bar_settings_mute_label" msgid="554682549917429396">"بی‌صدا"</string>
+    <string name="status_bar_settings_mute_label" msgid="554682549917429396">"صامت"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"خودکار"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"اعلان‌ها"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"اتصال اینترنتی با بلوتوث تلفن همراه"</string>
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"باز کردن دوربین"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"انتخاب طرح‌بندی جدید کار"</string>
     <string name="cancel" msgid="6442560571259935130">"لغو"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"بخش پیام راهنما"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"تأیید"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"حسگر اثر انگشت را لمس کنید"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"نماد اثر انگشت"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"نماد برنامه"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"بخش پیام راهنما"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"درحال جستجوی شما…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"نماد چهره"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"دکمه بزرگ‌نمایی سازگار."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"بزرگ‌نمایی از صفحه‌های کوچک تا بزرگ."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"بلوتوث متصل است."</string>
@@ -539,14 +541,14 @@
     <string name="ring_toggle_title" msgid="3281244519428819576">"تماس‌ها"</string>
     <string name="volume_ringer_status_normal" msgid="4273142424125855384">"زنگ زدن"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"لرزش"</string>
-    <string name="volume_ringer_status_silent" msgid="6896394161022916369">"بی‌صدا"</string>
+    <string name="volume_ringer_status_silent" msgid="6896394161022916369">"صامت"</string>
     <string name="qs_status_phone_vibrate" msgid="204362991135761679">"تلفن در حالت لرزش است"</string>
     <string name="qs_status_phone_muted" msgid="5437668875879171548">"تلفن بی‌صدا است"</string>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"‏%1$s. برای باصدا کردن ضربه بزنید."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"‏%1$s. برای تنظیم روی لرزش ضربه بزنید. ممکن است سرویس‌های دسترس‌پذیری بی‌صدا شوند."</string>
-    <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"‏%1$s. برای بی‌صدا کردن ضربه بزنید. ممکن است سرویس‌های دسترس‌پذیری بی‌صدا شوند."</string>
+    <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"‏%1$s. برای صامت کردن ضربه بزنید. ممکن است سرویس‌های دسترس‌پذیری صامت شود."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="6427727603978431301">"‏%1$s. برای تنظیم روی لرزش، ضربه بزنید."</string>
-    <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"‏%1$s. برای بی‌صدا کردن ضربه بزنید."</string>
+    <string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"‏%1$s. برای صامت کردن ضربه بزنید."</string>
     <string name="volume_ringer_hint_mute" msgid="9199811307292269601">"صامت کردن"</string>
     <string name="volume_ringer_hint_unmute" msgid="6602880133293060368">"باصدا کردن"</string>
     <string name="volume_ringer_hint_vibrate" msgid="4036802135666515202">"لرزش"</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"فضای ذخیره‌سازی"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"نکات"</string>
     <string name="instant_apps" msgid="6647570248119804907">"برنامه‌های فوری"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"برنامه‌های فوری نیاز به نصب ندارند."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> درحال اجرا"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"برنامه بدون نصب شدن باز شد."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"برنامه بدون نصب شدن باز شد. برای اطلاعات بیشتر ضربه بزنید."</string>
     <string name="app_info" msgid="6856026610594615344">"اطلاعات برنامه"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"رفتن به مرورگر"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"رفتن به وب"</string>
     <string name="mobile_data" msgid="7094582042819250762">"داده تلفن همراه"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"‏Wi-Fi خاموش است"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 83345b8..6e8cb4c 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"avaa kamera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Valitse uusi tehtävien asettelu"</string>
     <string name="cancel" msgid="6442560571259935130">"Peruuta"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Ohjeviestialue"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Vahvista"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Kosketa sormenjälkitunnistinta"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Sormenjälkikuvake"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Sovelluskuvake"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Ohjeviestialue"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Etsitään kasvoja…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Kasvokuvake"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Yhteensopivuuszoomaus-painike."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoomaa pienemmältä suuremmalle ruudulle."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth yhdistetty."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Tallennustila"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Vihjeet"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Pikasovelluksia ei tarvitse asentaa."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> on käynnissä"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Sovellus avattiin ilman asennusta."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Sovellus avattiin ilman asennusta. Katso lisätietoja napauttamalla."</string>
     <string name="app_info" msgid="6856026610594615344">"Sovelluksen tiedot"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Siirry selaimeen"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Avaa verkossa"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Mobiilitiedonsiirto"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi on pois käytöstä"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index c9c252f..f6d66b7 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"Ouvrir l\'appareil photo"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Sélectionner un nouveau format de tâche"</string>
     <string name="cancel" msgid="6442560571259935130">"Annuler"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Zone de message d\'aide"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirmer"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Touchez le capteur d\'empreintes digitales"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Icône d\'empreinte digitale"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Icône de l\'application"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Zone de message d\'aide"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Recherche de votre visage…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Icône de visage"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Bouton \"Zoom de compatibilité\""</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de compatibilité avec la taille de l\'écran"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connecté"</string>
@@ -825,9 +827,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Stockage"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Conseils"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Applications instantanées"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Les applications instantanées ne nécessitent pas d\'installation."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> en cours d\'exécution"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Application ouverte sans avoir été installée."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Application ouverte sans avoir été installée. Touchez ici pour en savoir plus."</string>
     <string name="app_info" msgid="6856026610594615344">"Détails de l\'application"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Ouvrir le navigateur"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Accéder au Web"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Données cellulaires"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> : <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Le Wi-Fi est désactivé"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 4559854..326b7c7 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"ouvrir l\'appareil photo"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Sélectionner un nouveau plan de tâche"</string>
     <string name="cancel" msgid="6442560571259935130">"Annuler"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Zone de message d\'aide"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirmer"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Appuyez sur le lecteur d\'empreinte digitale"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Icône d\'empreinte digitale"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Icône d\'application"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Zone de message d\'aide"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Recherche de votre visage…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Icône représentant un visage"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Bouton \"Zoom de compatibilité\""</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de compatibilité avec la taille de l\'écran"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connecté"</string>
@@ -401,9 +403,9 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Aucune\ninterruption"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priorité\nuniquement"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarmes\nuniquement"</string>
-    <string name="keyguard_indication_charging_time" msgid="2056340799276374421">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Rechargement… (rechargé à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>)"</string>
-    <string name="keyguard_indication_charging_time_fast" msgid="7767562163577492332">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Rechargement rapide… (à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>)"</string>
-    <string name="keyguard_indication_charging_time_slowly" msgid="3769655133567307069">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Rechargement lent… (à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time" msgid="2056340799276374421">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Recharge... (à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="7767562163577492332">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Recharge rapide… (à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="3769655133567307069">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Recharge lente… (à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Changer d\'utilisateur"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Changer d\'utilisateur (utilisateur actuel : <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Utilisateur actuel : <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -825,9 +827,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Espace de stockage"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Astuces"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Applis instantanées"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Les applis instantanées ne nécessitent pas d\'installation."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> en cours d\'exécution"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Vous pouvez ouvrir cette application sans l\'installer."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Vous pouvez ouvrir cette application sans l\'installer. Appuyez pour en savoir plus."</string>
     <string name="app_info" msgid="6856026610594615344">"Infos sur l\'appli"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Accéder au navigateur"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Accéder au site Web"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Données mobiles"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi désactivé"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 9cb251e..192c132 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"abrir cámara"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Seleccionar novo deseño de tarefas"</string>
     <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Área de mensaxes de axuda"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirmar"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Toca o sensor de impresión dixital"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Icona de impresión dixital"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Icona de aplicación"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Área de mensaxes de axuda"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Buscándote…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Icona de cara"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botón de zoom de compatibilidade"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de compatibilidade co tamaño da pantalla."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth conectado"</string>
@@ -825,9 +827,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Almacenamento"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Consellos"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Aplicacións instantáneas"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"As aplicacións instantáneas non precisan instalación."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"Estase executando <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Abriuse a aplicación sen ter que instalala."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Abriuse a aplicación sen ter que instalala. Tocar para obter máis información."</string>
     <string name="app_info" msgid="6856026610594615344">"Info. da aplicación"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Ir ao navegador"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Acceder á web"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Datos móbiles"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g>-<xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"A wifi está desactivada"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index df06cbe..f392268 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"કૅમેરો ખોલો"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"નવું કાર્ય લેઆઉટ પસંદ કરો"</string>
     <string name="cancel" msgid="6442560571259935130">"રદ કરો"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"સહાય સંદેશનું ક્ષેત્ર"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"કન્ફર્મ કરો"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"ફિંગરપ્રિન્ટના સેન્સરને સ્પર્શ કરો"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"ફિંગરપ્રિન્ટનું આઇકન"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"ઍપ્લિકેશનનું આઇકન"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"સહાય સંદેશનું ક્ષેત્ર"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"તમારા માટે શોધી રહ્યાં છે..."</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"ચહેરા આઇકન"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"સુસંગતતા ઝૂમ બટન."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"નાનીથી મોટી સ્ક્રીન પર ઝૂમ કરો."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"બ્લૂટૂથ કનેક્ટ થયું."</string>
@@ -823,9 +825,14 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"સ્ટોરેજ"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"હિન્ટ"</string>
     <string name="instant_apps" msgid="6647570248119804907">"ઝટપટ ઍપ્લિકેશનો"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"ઝટપટ ઍપ્લિકેશનો માટે ઇન્સ્ટૉલેશનની જરૂર નથી."</string>
+    <!-- no translation found for instant_apps_title (8738419517367449783) -->
+    <skip />
+    <!-- no translation found for instant_apps_message (1183313016396018086) -->
+    <skip />
+    <!-- no translation found for instant_apps_message_with_help (6179830437630729747) -->
+    <skip />
     <string name="app_info" msgid="6856026610594615344">"ઍપ્લિકેશન માહિતી"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"બ્રાઉઝર પર જાઓ"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"વેબ પર જાઓ"</string>
     <string name="mobile_data" msgid="7094582042819250762">"મોબાઇલ ડેટા"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"વાઇ-ફાઇ બંધ છે"</string>
diff --git a/packages/SystemUI/res/values-h320dp/config.xml b/packages/SystemUI/res/values-h320dp/config.xml
deleted file mode 100644
index a9c19db..0000000
--- a/packages/SystemUI/res/values-h320dp/config.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (c) 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-*/
--->
-
-<resources>
-    <!-- The number of rows in the QuickSettings -->
-    <integer name="quick_settings_num_rows">2</integer>
-</resources>
diff --git a/packages/SystemUI/res/values-h600dp/config.xml b/packages/SystemUI/res/values-h600dp/config.xml
deleted file mode 100644
index 8616e3e..0000000
--- a/packages/SystemUI/res/values-h600dp/config.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (c) 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-*/
--->
-
-<resources>
-    <!-- The number of rows in the QuickSettings -->
-    <integer name="quick_settings_num_rows">3</integer>
-</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 46555a4..8795264 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"कैमरा खोलें"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"नया कार्य लेआउट चुनें"</string>
     <string name="cancel" msgid="6442560571259935130">"रद्द करें"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"सहायता का मैसेज दिखाने की जगह"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"पुष्टि करें"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"फ़िंगरप्रिंट सेंसर को छुएं"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"फ़िंगरप्रिंट आइकॉन"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"ऐप्लिकेशन आइकॉन"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"सहायता का मैसेज दिखाने की जगह"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"आपको पहचान रहा है…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"चेहरे का आइकॉन"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"संगतता ज़ूम बटन."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"छोटी से बड़ी स्‍क्रीन पर ज़ूम करें."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ब्लूटूथ कनेक्ट किया गया."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"जगह"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"संकेत"</string>
     <string name="instant_apps" msgid="6647570248119804907">"इंस्टेंट ऐप"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"झटपट ऐप्स के लिए इंस्टॉलेशन ज़रूरी नहीं है."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> चल रहा है"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"ऐप्लिकेशन इंस्टॉल किए बिना ही खुल गया है."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"ऐप्लिकेशन इंस्टॉल किए बिना ही खुल गया है. ज़्यादा जानने के लिए टैप करें."</string>
     <string name="app_info" msgid="6856026610594615344">"ऐप की जानकारी"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"ब्राउज़र पर जाएं"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"वेब पर जाएं"</string>
     <string name="mobile_data" msgid="7094582042819250762">"मोबाइल डेटा"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"वाई-फ़ाई बंद है"</string>
diff --git a/packages/SystemUI/res/values-hi/strings_car.xml b/packages/SystemUI/res/values-hi/strings_car.xml
index 8820046..3beada5 100644
--- a/packages/SystemUI/res/values-hi/strings_car.xml
+++ b/packages/SystemUI/res/values-hi/strings_car.xml
@@ -20,8 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="car_guest" msgid="3738772168718508650">"मेहमान"</string>
-    <!-- no translation found for start_guest_session (7055742120180595689) -->
-    <skip />
+    <string name="start_guest_session" msgid="7055742120180595689">"मेहमान मोड"</string>
     <string name="car_add_user" msgid="5245196248349230898">"उपयोगकर्ता जोड़ें"</string>
     <string name="car_new_user" msgid="8142927244990323906">"नया उपयोगकर्ता"</string>
     <string name="user_add_user_message_setup" msgid="1791011504259527329">"जब आप कोई नया उपयोगकर्ता जोड़ते हैं तो, उस व्यक्ति को अपनी जगह सेट करनी होती है."</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 7ad2fe2..b6fa4f5 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -104,10 +104,12 @@
     <string name="camera_label" msgid="7261107956054836961">"otvaranje fotoaparata"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Odaberite novi izgled zadataka"</string>
     <string name="cancel" msgid="6442560571259935130">"Odustani"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Područje poruke za pomoć"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Potvrdi"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Dodirnite senzor otiska prsta"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikona otiska prsta"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Ikona aplikacije"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Područje poruke za pomoć"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Tražimo vas…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ikona lica"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Gumb za kompatibilnost zumiranja."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zumiranje manjeg zaslona na veći."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth povezan."</string>
@@ -829,9 +831,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Pohrana"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Savjeti"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Instant aplikacije"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Instant aplikacije nije potrebno instalirati."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"Izvodi se aplikacija <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Aplikacija je otvorena bez instaliranja."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Aplikacija je otvorena bez instaliranja. Dodirnite da biste saznali više."</string>
     <string name="app_info" msgid="6856026610594615344">"Informacije o aplikaciji"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Otvori preglednik"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Prijeđi na web"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Mobilni podaci"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi je isključen"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index f5fad27..9076379 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"kamera megnyitása"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Új feladatelrendezés kiválasztása"</string>
     <string name="cancel" msgid="6442560571259935130">"Mégse"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Súgószöveg területe"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Megerősítés"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Érintse meg az ujjlenyomat-érzékelőt"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ujjlenyomat ikonja"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Alkalmazás ikonja"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Súgószöveg területe"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Keresem az Ön arcát…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Arcikon"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Kompatibilitási zoom gomb."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kicsinyítsen a nagyobb képernyőhöz."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth csatlakoztatva."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Tárhely"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Tippek"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Azonnali alkalmazások"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Az azonnali alkalmazásokat nem kell telepíteni."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"A(z) <xliff:g id="APP">%1$s</xliff:g> alkalmazás jelenleg fut"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Az alkalmazás telepítés nélkül lett megnyitva."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Az alkalmazás telepítés nélkül lett megnyitva. Ha további információra van szüksége, koppintson ide."</string>
     <string name="app_info" msgid="6856026610594615344">"Alkalmazásinformáció"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Ugrás a böngészőbe"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Tovább az internetre"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Mobiladatok"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"A Wi-Fi ki van kapcsolva"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 5eeca4c..54401f5 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"բացել ֆոտոխցիկը"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Ընտրել առաջադրանքի նոր դասավորություն"</string>
     <string name="cancel" msgid="6442560571259935130">"Չեղարկել"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Օգնության հաղորդագրության դաշտ"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Հաստատել"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Հպեք մատնահետքերի սկաներին"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Մատնահետքի պատկերակ"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Հավելվածի պատկերակ"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Օգնության հաղորդագրության դաշտ"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Դեմքի ճանաչում…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Դեմքի պատկերակ"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Համատեղելիության խոշորացման կոճակը:"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Դիտափոխել փոքրից ավելի մեծ էկրան:"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth-ը միացված է:"</string>
@@ -582,12 +584,12 @@
     <string name="accessibility_status_bar_hotspot" msgid="4099381329956402865">"Թեժ կետ"</string>
     <string name="accessibility_managed_profile" msgid="6613641363112584120">"Աշխատանքային պրոֆիլ"</string>
     <string name="tuner_warning_title" msgid="7094689930793031682">"Զվարճանք մեկ՝ որոշակի մարդու համար"</string>
-    <string name="tuner_warning" msgid="8730648121973575701">"Համակարգի ՕՄ-ի ընդունիչը հնարավորություն է տալիս հարմարեցնել Android-ի օգտատիրոջ միջերեսը: Այս փորձնական գործառույթները կարող են հետագա թողարկումների մեջ փոփոխվել, խափանվել կամ ընդհանրապես չհայտնվել: Եթե շարունակում եք, զգուշացեք:"</string>
+    <string name="tuner_warning" msgid="8730648121973575701">"Համակարգի ՕՄ-ի կարգավորիչը հնարավորություն է տալիս հարմարեցնել Android-ի օգտատիրոջ միջերեսը: Այս փորձնական գործառույթները կարող են հետագա թողարկումների մեջ փոփոխվել, խափանվել կամ ընդհանրապես չհայտնվել: Եթե շարունակում եք, զգուշացեք:"</string>
     <string name="tuner_persistent_warning" msgid="8597333795565621795">"Այս փորձնական գործառույթները կարող են հետագա թողարկումների մեջ փոփոխվել, խափանվել կամ ընդհանրապես չհայտնվել: Եթե շարունակում եք, զգուշացեք:"</string>
     <string name="got_it" msgid="2239653834387972602">"Եղավ"</string>
-    <string name="tuner_toast" msgid="603429811084428439">"Համակարգի ՕՄ-ի ընդունիչը ավելացվել է կարգավորումներին"</string>
+    <string name="tuner_toast" msgid="603429811084428439">"Համակարգի ՕՄ-ի կարգավորիչը ավելացվել է կարգավորումներին"</string>
     <string name="remove_from_settings" msgid="8389591916603406378">"Հեռացնել կարգավորումներից"</string>
-    <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Հեռացնե՞լ Համակարգի ՕՄ-ի ընդունիչը կարգավորումներից և չօգտվել այլևս նրա գործառույթներից:"</string>
+    <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Հեռացնե՞լ Համակարգի ՕՄ-ի կարգավորիչը կարգավորումներից և չօգտվել այլևս նրա գործառույթներից:"</string>
     <string name="activity_not_found" msgid="348423244327799974">"Հավելվածը տեղադրված չէ սարքի վրա"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Ցույց տալ ժամացույցի վայրկյանները"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Ցույց տալ ժամացույցի վայրկյանները կարգավիճակի տողում: Կարող է ազդել մարտկոցի աշխատանքի ժամանակի վրա:"</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Տարածք"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Հուշումներ"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Ակնթարթային հավելվածներ"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Ակնթարթային հավելվածները տեղադրում չեն պահանջում։"</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> հավելվածն աշխատում է"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Հավելվածը բացվել է առանց տեղադրման։"</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Հավելվածը բացվել է առանց տեղադրման։ Հպեք՝ ավելին իմանալու համար։"</string>
     <string name="app_info" msgid="6856026610594615344">"Հավելվածի տվյալներ"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Անցնել դիտարկիչ"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Բացեք համացանցում"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Բջջային ինտերնետ"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi-ն անջատված է"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 5a61a64..2474158 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"buka kamera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Pilih tata letak tugas baru"</string>
     <string name="cancel" msgid="6442560571259935130">"Batal"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Area pesan bantuan"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Konfirmasi"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Sentuh sensor sidik jari"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikon sidik jari"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Ikon aplikasi"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Area pesan bantuan"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Mencari wajah Anda…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ikon wajah"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Tombol perbesar/perkecil kompatibilitas."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Perbesar dari layar kecil ke besar."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth tersambung."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Penyimpanan"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Petunjuk"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Aplikasi Instan"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Aplikasi instan tidak perlu diinstal."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> berjalan"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Aplikasi dapat dibuka tanpa perlu diinstal."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Aplikasi dapat dibuka tanpa perlu diinstal. Tap untuk mempelajari lebih lanjut."</string>
     <string name="app_info" msgid="6856026610594615344">"Info aplikasi"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Buka browser"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Buka di web"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Data seluler"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi nonaktif"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index fb83ff07..c2a020b 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"opna myndavél"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Velja nýtt útlit verkefna"</string>
     <string name="cancel" msgid="6442560571259935130">"Hætta við"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Svæði hjálparskilaboða"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Staðfesta"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Snertu fingrafaralesarann"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Fingrafaratákn"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Forritstákn"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Svæði hjálparskilaboða"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Leitar að þér ..."</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Andlitstákn"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Hnappur fyrir samhæfisaðdrátt."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Aðlaga forrit fyrir lítinn skjá að stærri skjá."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth tengt."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Geymslurými"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Vísbendingar"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Skyndiforrit"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Skyndiforrit þurfa ekki uppsetningu."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> er í gangi"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Forrit opnað án þess að vera uppsett."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Forrit opnað án þess að vera uppsett. Ýttu til að fá frekari upplýsingar."</string>
     <string name="app_info" msgid="6856026610594615344">"Forritsupplýsingar"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Opna vafra"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Fara á vefinn"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Farsímagögn"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Slökkt á Wi-Fi"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index c081eaa..aefaa6d 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"apri fotocamera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Seleziona un nuovo layout per le attività"</string>
     <string name="cancel" msgid="6442560571259935130">"Annulla"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Area dei messaggi di assistenza"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confermo"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Tocca il sensore di impronte digitali"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Icona dell\'impronta digitale"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Icona dell\'applicazione"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Area dei messaggi di assistenza"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"In attesa del volto…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Icona volto"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Pulsante zoom compatibilità."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom inferiore per schermo più grande."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth collegato."</string>
@@ -825,9 +827,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Spazio di archiviazione"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Suggerimenti"</string>
     <string name="instant_apps" msgid="6647570248119804907">"App istantanee"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Le app istantanee non richiedono l\'installazione."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"App <xliff:g id="APP">%1$s</xliff:g> in esecuzione"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"App aperta senza essere stata installata."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"App aperta senza essere stata installata. Tocca per avere ulteriori informazioni."</string>
     <string name="app_info" msgid="6856026610594615344">"Informazioni app"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Vai al browser"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Vai sul Web"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Dati mobili"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> - <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi disattivato"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index d3d18ae..b83f5df 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -105,10 +105,12 @@
     <string name="camera_label" msgid="7261107956054836961">"פתח את המצלמה"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"בחר פריסה חדשה להצגת משימות"</string>
     <string name="cancel" msgid="6442560571259935130">"ביטול"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"אזור הודעת עזרה"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"אישור"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"יש לגעת בחיישן טביעות האצבע"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"סמל טביעת אצבע"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"סמל אפליקציה"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"אזור הודעת עזרה"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"מחפש אותך…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"סמל הפנים"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"לחצן מרחק מתצוגה של תאימות."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"שנה מרחק מתצוגה של מסך קטן לגדול יותר."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"‏Bluetooth מחובר."</string>
@@ -194,7 +196,7 @@
     <string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"פתח מידע על האפליקציה <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"מפעיל את <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"הודעה נדחתה."</string>
-    <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"לוח הודעות."</string>
+    <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"לוח התראות."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"הגדרות מהירות."</string>
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"מסך נעילה."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"הגדרות"</string>
@@ -266,7 +268,7 @@
       <item quantity="other">יש בפנים עוד <xliff:g id="NUMBER_1">%s</xliff:g> הודעות.</item>
       <item quantity="one">יש בפנים עוד הודעה <xliff:g id="NUMBER_0">%s</xliff:g>.</item>
     </plurals>
-    <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"הגדרות עבור הודעות"</string>
+    <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"הגדרת התראות"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"הגדרות <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"המסך יסתובב באופן אוטומטי."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"המסך נעול כעת לרוחב."</string>
@@ -835,9 +837,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"אחסון"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"טיפים"</string>
     <string name="instant_apps" msgid="6647570248119804907">"אפליקציות אינסטנט"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"אפליקציות אינסטנט לא דורשות התקנה."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> פועלת"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"האפליקציה נפתחת בלי התקנה."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"האפליקציה נפתחת בלי התקנה. אפשר להקיש כדי לקבל מידע נוסף."</string>
     <string name="app_info" msgid="6856026610594615344">"פרטי אפליקציה"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"מעבר אל הדפדפן"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"התחבר לאינטרנט"</string>
     <string name="mobile_data" msgid="7094582042819250762">"נתונים סלולריים"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> ‏— <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"‏Wi-Fi כבוי"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 8377f07..e5b0a2b 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"カメラを起動"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"新しいタスクレイアウトの選択"</string>
     <string name="cancel" msgid="6442560571259935130">"キャンセル"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"ヘルプ メッセージ領域"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"確認"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"指紋認証センサーをタップしてください"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"指紋アイコン"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"アプリのアイコン"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"ヘルプ メッセージ領域"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"顔を認証しています…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"顔アイコン"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"互換ズームボタン。"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"小さい画面から大きい画面に拡大。"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetoothに接続済み。"</string>
@@ -346,7 +348,7 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"上限: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"警告: 上限は<xliff:g id="DATA_LIMIT">%s</xliff:g>です"</string>
     <string name="quick_settings_work_mode_label" msgid="7608026833638817218">"仕事用プロファイル"</string>
-    <string name="quick_settings_night_display_label" msgid="3577098011487644395">"読書灯"</string>
+    <string name="quick_settings_night_display_label" msgid="3577098011487644395">"夜間モード"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"日の入りに ON"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"日の出まで"</string>
     <string name="quick_settings_night_secondary_label_on_at" msgid="6256314040368487637">"<xliff:g id="TIME">%s</xliff:g> に ON"</string>
@@ -825,9 +827,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"ストレージ"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"ヒント"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Instant Apps はインストールせずに利用できます。"</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> を実行中"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"アプリをインストールせずに開きました。"</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"アプリをインストールせずに開きました。詳細を見るにはタップしてください。"</string>
     <string name="app_info" msgid="6856026610594615344">"アプリ情報"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"ブラウザに移動"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"ウェブページを開く"</string>
     <string name="mobile_data" msgid="7094582042819250762">"モバイルデータ"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi は OFF です"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index fb880c7..19e9f47 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"კამერის გახსნა"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"ახალი ამოცანის განლაგების არჩევა"</string>
     <string name="cancel" msgid="6442560571259935130">"გაუქმება"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"დამხმარე შეტყობინების არე"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"დადასტურება"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"შეეხეთ თითის ანაბეჭდის სენსორს"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"თითის ანაბეჭდის ხატულა"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"აპლიკაციის ხატულა"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"დახმარების შეტყობინების არეალი"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"მიმდინარეობს თქვენი ძიება…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"სახის ხატულა"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"თავსებადი მასშტაბირების ღილაკი."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"შეცვალეთ პატარა ეკრანი უფრო დიდით."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth დაკავშირებულია."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"მეხსიერება"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"მინიშნებები"</string>
     <string name="instant_apps" msgid="6647570248119804907">"მყისიერი აპები"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"მყისიერი აპები ინსტალაციას არ საჭიროებს."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> გაშვებულია"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"აპი გაიხსნა ინსტალაციის გარეშე."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"აპი გაიხსნა ინსტალაციის გარეშე. შეეხეთ მეტის გასაგებად."</string>
     <string name="app_info" msgid="6856026610594615344">"აპის შესახებ"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"ბრაუზერზე გადასვლა"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"ვებზე გადასვლა"</string>
     <string name="mobile_data" msgid="7094582042819250762">"მობილური ინტერნეტი"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi გამორთულია"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 6e372d7..15f8cd5 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"камераны ашу"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Жаңа тапсырма пішімін таңдау"</string>
     <string name="cancel" msgid="6442560571259935130">"Бас тарту"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Анықтама хабары аумағы"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Растау"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Саусақ ізін оқу сканерін түртіңіз"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Саусақ ізі белгішесі"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Қолданба белгішесі"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Анықтама хабары аумағы"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Бет ізделуде…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Бет белгішесі"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Үйлесімділік ұлғайту түймесі."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Үлкендеу экранда кішірейту."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth қосылған."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Жад"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Кеңестер"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Лездік қолданбаларды орнатудың қажеті жоқ."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> іске қосулы"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Қолданба орнатылмай-ақ ашылды."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Қолданба орнатылмай-ақ ашылды. Толығырақ мәлімет алу үшін түртіңіз."</string>
     <string name="app_info" msgid="6856026610594615344">"Қолданба ақпараты"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Браузерге өту"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Вебке өту"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Мобильдік деректер"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi өшірулі"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index eb9ed61..af8d4ce 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"បើក​ម៉ាស៊ីន​ថត"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"ជ្រើសប្លង់ភារកិច្ចថ្មី"</string>
     <string name="cancel" msgid="6442560571259935130">"បោះ​បង់​"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"តំបន់សារ​ជំនួយ"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"បញ្ជាក់"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"ប៉ះ​ឧបករណ៍​ចាប់ស្នាម​ម្រាមដៃ"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"រូបតំណាង​ស្នាម​ម្រាមដៃ"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"រូបតំណាង​កម្មវិធី"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"តំបន់សារ​ជំនួយ"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"កំពុងស្វែងរកអ្នក…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"រូប​ផ្ទៃមុខ"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ប៊ូតុង​ពង្រីក​ត្រូវ​គ្នា។"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ពង្រីក/បង្រួម​​អេក្រង់​ពី​​ទៅធំ"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"បាន​តភ្ជាប់​ប៊្លូធូស។"</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"ទំហំផ្ទុក"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"ការ​សម្រួល"</string>
     <string name="instant_apps" msgid="6647570248119804907">"កម្មវិធី​ប្រើ​ភ្លាមៗ"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"កម្មវិធី​ប្រើ​ភ្លាមៗ​មិន​តម្រូវ​ឲ្យ​មានការ​ដំឡើង​ទេ។"</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> កំពុង​ដំណើរការ"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"កម្មវិធីត្រូវ​បាន​បើក​ដោយ​មិនចាំបាច់ដំឡើង។"</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"កម្មវិធីត្រូវ​បាន​បើក​ដោយ​មិនចាំបាច់ដំឡើង។ ចុច​ដើម្បី​ស្វែងយល់បន្ថែម។"</string>
     <string name="app_info" msgid="6856026610594615344">"ព័ត៌មាន​កម្មវិធី"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"ចូល​ទៅ​កម្មវិធី​រុករក​តាម​អ៊ីនធឺណិត"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"ចូលទៅកាន់បណ្តាញ"</string>
     <string name="mobile_data" msgid="7094582042819250762">"ទិន្នន័យ​ទូរសព្ទចល័ត"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi បាន​បិទ"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index c63dbe9..ac36e73 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"ಕ್ಯಾಮರಾ ತೆರೆಯಿರಿ"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"ಹೊಸ ಕಾರ್ಯ ವಿನ್ಯಾಸವನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
     <string name="cancel" msgid="6442560571259935130">"ರದ್ದುಮಾಡಿ"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"ಸಹಾಯ ಸಂದೇಶ ಪ್ರದೇಶ"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"ದೃಢೀಕರಿಸಿ"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್‌‌ ಅನ್ನು ಸ್ಪರ್ಶಿಸಿ"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಐಕಾನ್"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"ಅಪ್ಲಿಕೇಶನ್‌ ಐಕಾನ್‌"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"ಸಹಾಯ ಸಂದೇಶ ಪ್ರದೇಶ"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"ನಿಮಗಾಗಿ ಹುಡುಕಲಾಗುತ್ತಿದೆ…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"ಮುಖದ ಐಕಾನ್‌"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ಹೊಂದಾಣಿಕೆಯ ಝೂಮ್ ಬಟನ್."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ಚಿಕ್ಕ ಪರದೆಯಿಂದ ದೊಡ್ಡ ಪರದೆಗೆ ಝೂಮ್ ಮಾಡು."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ಬ್ಲೂಟೂತ್‌‌ ಸಂಪರ್ಕಗೊಂಡಿದೆ."</string>
@@ -823,9 +825,14 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"ಸಂಗ್ರಹಣೆ"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"ಸುಳಿವುಗಳು"</string>
     <string name="instant_apps" msgid="6647570248119804907">"ತತ್‌ಕ್ಷಣ ಆಪ್‌ಗಳು"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"ತತ್‌ಕ್ಷಣ ಆಪ್‌ಗಳಿಗೆ ಸ್ಥಾಪನೆಯ ಅಗತ್ಯವಿಲ್ಲ."</string>
+    <!-- no translation found for instant_apps_title (8738419517367449783) -->
+    <skip />
+    <!-- no translation found for instant_apps_message (1183313016396018086) -->
+    <skip />
+    <!-- no translation found for instant_apps_message_with_help (6179830437630729747) -->
+    <skip />
     <string name="app_info" msgid="6856026610594615344">"ಅಪ್ಲಿಕೇಶನ್ ಮಾಹಿತಿ"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"ಬ್ರೌಸರ್‌ಗೆ ಹೋಗಿ"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"ವೆಬ್‌ಗೆ ಹೋಗಿ"</string>
     <string name="mobile_data" msgid="7094582042819250762">"ಮೊಬೈಲ್ ಡೇಟಾ"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"ವೈ-ಫೈ ಆಫ್ ಆಗಿದೆ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 77c983e..1e2ab42 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"카메라 열기"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"새 작업 레이아웃 선택"</string>
     <string name="cancel" msgid="6442560571259935130">"취소"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"도움말 메시지 영역"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"확인"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"지문 센서를 터치하세요."</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"지문 아이콘"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"애플리케이션 아이콘"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"도움말 메시지 영역"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"찾는 중..."</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"얼굴 아이콘"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"호환성 확대/축소 버튼입니다."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"작은 화면을 큰 화면으로 확대합니다."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"블루투스가 연결되었습니다."</string>
@@ -410,13 +412,13 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="3020367729287990475">"프로필 표시"</string>
     <string name="user_add_user" msgid="5110251524486079492">"사용자 추가"</string>
     <string name="user_new_user_name" msgid="426540612051178753">"새 사용자"</string>
-    <string name="guest_nickname" msgid="8059989128963789678">"손님"</string>
+    <string name="guest_nickname" msgid="8059989128963789678">"게스트"</string>
     <string name="guest_new_guest" msgid="600537543078847803">"게스트 추가"</string>
-    <string name="guest_exit_guest" msgid="7187359342030096885">"손님 삭제"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="8480693520521766688">"손님을 삭제하시겠습니까?"</string>
+    <string name="guest_exit_guest" msgid="7187359342030096885">"게스트 삭제"</string>
+    <string name="guest_exit_guest_dialog_title" msgid="8480693520521766688">"게스트를 삭제하시겠습니까?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="4155503224769676625">"이 세션에 있는 모든 앱과 데이터가 삭제됩니다."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7402231963862520531">"삭제"</string>
-    <string name="guest_wipe_session_title" msgid="6419439912885956132">"손님 세션 다시 시작"</string>
+    <string name="guest_wipe_session_title" msgid="6419439912885956132">"게스트 세션 다시 시작"</string>
     <string name="guest_wipe_session_message" msgid="8476238178270112811">"세션을 계속 진행하시겠습니까?"</string>
     <string name="guest_wipe_session_wipe" msgid="5065558566939858884">"다시 시작"</string>
     <string name="guest_wipe_session_dontwipe" msgid="1401113462524894716">"예, 계속합니다."</string>
@@ -825,9 +827,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"저장공간"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"힌트"</string>
     <string name="instant_apps" msgid="6647570248119804907">"인스턴트 앱"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"인스턴트 앱은 설치가 필요하지 않습니다."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> 실행 중"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"설치 없이 앱이 실행되었습니다."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"설치 없이 앱이 실행되었습니다. 탭하여 자세히 알아보세요."</string>
     <string name="app_info" msgid="6856026610594615344">"앱 정보"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"브라우저로 이동"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"웹으로 이동"</string>
     <string name="mobile_data" msgid="7094582042819250762">"모바일 데이터"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi가 사용 중지됨"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index e334da4..585e290 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"камераны ачуу"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Жаңы тапшырманын планын тандаңыз"</string>
     <string name="cancel" msgid="6442560571259935130">"Жокко чыгаруу"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Жардам билдирүүсү"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Ырастоо"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Манжа изинин сенсорун басыңыз"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Манжа изинин сүрөтчөсү"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Колдонмонун сүрөтчөсү"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Жардам билдирүүсү"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Жүзүңүз изделүүдө…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Жүздүн сүрөтчөсү"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Масштабды сыйыштыруу баскычы."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Кичинекейди чоң экранга масштабдоо."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth байланышта"</string>
@@ -209,7 +211,7 @@
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Учак режими өчүрүлдү."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Учак режими күйгүзүлдү."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="2960643943620637020">"тымтырс"</string>
-    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="3357131899365865386">"ойготкучтар гана"</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="3357131899365865386">"ойготкуч гана"</string>
     <string name="accessibility_quick_settings_dnd" msgid="6607873236717185815">"Тынчымды алба."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Тынчымды алба деген өчүрүлдү."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Тынчымды алба деген күйгүзүлдү."</string>
@@ -276,7 +278,7 @@
     <string name="quick_settings_header_onboarding_text" msgid="8030309023792936283">"Кошумча параметрлерди ачуу үчүн сүрөтчөлөрдү басып, кармап туруңуз"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Тынчымды алба"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Шашылыш эскертмелер гана"</string>
-    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Ойготкучтар гана"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Ойготкуч гана"</string>
     <string name="quick_settings_dnd_none_label" msgid="5025477807123029478">"Тымтырс"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> түзмөк)"</string>
@@ -395,7 +397,7 @@
     <string name="interruption_level_none_with_warning" msgid="5114872171614161084">"Толук жымжырттык талап кылынат. Бул экрандагыны окугучтарды да тынчтандырат."</string>
     <string name="interruption_level_none" msgid="6000083681244492992">"Тымтырс"</string>
     <string name="interruption_level_priority" msgid="6426766465363855505">"Шашылыш эскертмелер гана"</string>
-    <string name="interruption_level_alarms" msgid="5226306993448328896">"Ойготкучтар гана"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Ойготкуч гана"</string>
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Тым-\nтырс"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Артыкчылыктуу\nгана"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Ойготкучтар\nгана"</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Сактагыч"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Кеңештер"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Ыкчам ачылуучу колдонмолор"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Ыкчам ачылуучу колдонмолорду орнотуу талап кылынбайт."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> иштеп жатат"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Колдонмо орнотулбастан ачылды."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Колдонмо орнотулбастан ачылды. Толугураак маалымат алуу үчүн таптап коюңуз."</string>
     <string name="app_info" msgid="6856026610594615344">"Колдонмо тууралуу"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Серепчиге өтүү"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Интернетке өтүү"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Мобилдик Интернет"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi өчүк"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 56f9e1d..0952df4 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"ເປີດ​ກ້ອງ"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"ເລືອກ​ແຜນ​ຜັງ​ໜ້າ​ວຽກ​ໃໝ່"</string>
     <string name="cancel" msgid="6442560571259935130">"ຍົກເລີກ"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"ຊ່ວຍພື້ນທີ່ຂໍ້ຄວາມ"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"ຢືນຢັນ"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Touch the fingerprint sensor"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"ໄອຄອນລາຍນິ້ວມື"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"ໄອຄອນແອັບພລິເຄຊັນ"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"ຊ່ວຍພື້ນທີ່ຂໍ້ຄວາມ"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"ກຳລັງຊອກຫາທ່ານ…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"ໄອຄອນໃບໜ້າ"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ປຸ່ມຊູມທີ່ໃຊ້ຮ່ວມກັນໄດ້."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ຊູມຈໍນ້ອຍໄປເປັນຈໍຂະຫນາດໃຫຍ່."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ເຊື່ອມຕໍ່ Bluetooth ແລ້ວ."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"ບ່ອນເກັບຂໍ້ມູນ"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"ຄຳໃບ້"</string>
     <string name="instant_apps" msgid="6647570248119804907">"ອິນສະແຕນແອັບ"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"ອິນສະແຕນແອັບບໍ່ຈຳເປັນຕ້ອງມີການຕິດຕັ້ງ."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> ກຳລັງເຮັດວຽກຢູ່"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"ເປີດແອັບໂດຍບໍ່ມີການຕິດຕັ້ງແລ້ວ."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"ເປີດແອັບໂດຍບໍ່ມີການຕິດຕັ້ງແລ້ວ. ແຕະເພື່ອສຶກສາເພີ່ມເຕີມ."</string>
     <string name="app_info" msgid="6856026610594615344">"ຂໍ້ມູນແອັບ"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"ໄປທີ່ໂປຣແກຣມທ່ອງເວັບ"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"ໄປທີ່ເວັບ"</string>
     <string name="mobile_data" msgid="7094582042819250762">"ອິນເຕີເນັດມືຖື"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi ປິດຢູ່"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index b8ae38b..ac6cfc7 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -105,10 +105,12 @@
     <string name="camera_label" msgid="7261107956054836961">"atidaryti fotoaparatą"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Pasirinkti naują užduoties išdėstymą"</string>
     <string name="cancel" msgid="6442560571259935130">"Atšaukti"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Pagalbos pranešimo sritis"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Patvirtinkite"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Palieskite kontrolinio kodo jutiklį"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Kontrolinio kodo piktograma"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Programos piktograma"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Pagalbos pranešimo sritis"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Ieškoma jūsų…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Veido piktograma"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Suderinamumo priartinimo mygtukas."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Padidinti ekraną."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"„Bluetooth“ prijungtas."</string>
@@ -835,9 +837,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Saugykla"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Užuominos"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Akimirksniu įkeliamos programos"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Akimirksniu įkeliamų programų nereikia įdiegti."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"Programa „<xliff:g id="APP">%1$s</xliff:g>“ paleista"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Programa atidaryta jos neįdiegus."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Programa atidaryta jos neįdiegus. Palieskite, kad sužinotumėte daugiau."</string>
     <string name="app_info" msgid="6856026610594615344">"Programos informacija"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Eiti į naršyklę"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Eiti į žiniatinklį"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Mobilieji duomenys"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g>–<xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"„Wi-Fi“ išjungtas"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 4a0ee10..01e2e39 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -104,10 +104,12 @@
     <string name="camera_label" msgid="7261107956054836961">"atvērt kameru"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Atlasiet jaunu uzdevumu izkārtojumu"</string>
     <string name="cancel" msgid="6442560571259935130">"Atcelt"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Palīdzības ziņojuma apgabals"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Apstiprināt"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Pieskarieties pirksta nospieduma sensoram"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Pirksta nospieduma ikona"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Lietojumprogrammas ikona"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Palīdzības ziņojuma apgabals"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Notiek jūsu sejas meklēšana…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Sejas ikona"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Saderības tālummaiņas poga."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Veikt tālummaiņu no mazāka ekrāna uz lielāku."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth savienojums ir izveidots."</string>
@@ -829,9 +831,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Krātuve"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Padomi"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Tūlītējās lietotnes"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Tūlītējām lietotnēm nav nepieciešama instalēšana."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"Lietotne <xliff:g id="APP">%1$s</xliff:g> darbojas"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Lai atvērtu šo lietotni, tā nav jāinstalē."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Lai atvērtu šo lietotni, tā nav jāinstalē. Pieskarieties, lai uzzinātu vairāk."</string>
     <string name="app_info" msgid="6856026610594615344">"Lietotnes informācija"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Atvērt pārlūku"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Pāriet uz tīmekli"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Mobilie dati"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi ir izslēgts"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index bf9cc35..8b4b458 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"отвори камера"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Изберете нов распоред на задача"</string>
     <string name="cancel" msgid="6442560571259935130">"Откажи"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Област за пораки за помош"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Потврди"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Допрете го сензорот за отпечатоци"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Икона за отпечатоци"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Икона за апликацијата"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Поле за пораки за помош"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Ве бараме вас…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Икона за лице"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Копче за компатибилност на зум."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Зумот е помал на поголем екран."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth е поврзан."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Капацитет"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Совети"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Инстант апликации"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Инстант апликациите нема потреба да се инсталираат."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"Се извршува <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Апликацијата беше отворена без да се инсталира."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Апликацијата беше отворена без да се инсталира. Допрете за да дознаете повеќе."</string>
     <string name="app_info" msgid="6856026610594615344">"Информации за апликација"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Одете на прелистувач"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Одете на интернет"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Мобилен интернет"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> - <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi е исклучено"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index fefd073..fc32b88 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"ക്യാമറ തുറക്കുക"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"പുതിയ ടാസ്‌ക് ലേഔട്ട് തിരഞ്ഞെടുക്കുക"</string>
     <string name="cancel" msgid="6442560571259935130">"റദ്ദാക്കുക"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"സഹായ സന്ദേശ ഏരിയ"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"സ്ഥിരീകരിക്കുക"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"വിരലടയാള സെൻസർ സ്‌പർശിക്കുക"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"വിരലടയാള ഐക്കൺ"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"ആപ്പ് ഐക്കൺ"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"സഹായ സന്ദേശ ഏരിയ"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"നിങ്ങൾക്കായി തിരയുന്നു…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"മുഖത്തിന്റെ ഐക്കൺ"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"അനുയോജ്യതാ സൂം ബട്ടൺ."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ചെറുതിൽ നിന്ന് വലിയ സ്‌ക്രീനിലേക്ക് സൂം ചെയ്യുക."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ബ്ലൂടൂത്ത് കണക്‌റ്റുചെയ്തു."</string>
@@ -823,9 +825,14 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"സ്റ്റോറേജ്"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"സൂചനകൾ"</string>
     <string name="instant_apps" msgid="6647570248119804907">"ഇൻസ്റ്റന്റ് ആപ്പ്"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"ഇൻസ്‌റ്റ‌ന്റ് ആപ്പിന് ഇൻസ്‌റ്റലേഷൻ ആവശ്യമില്ല."</string>
+    <!-- no translation found for instant_apps_title (8738419517367449783) -->
+    <skip />
+    <!-- no translation found for instant_apps_message (1183313016396018086) -->
+    <skip />
+    <!-- no translation found for instant_apps_message_with_help (6179830437630729747) -->
+    <skip />
     <string name="app_info" msgid="6856026610594615344">"ആപ്പ് വിവരം"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"ബ്രൗസറിലേക്ക് പോവുക"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"വെബിൽ പോവുക"</string>
     <string name="mobile_data" msgid="7094582042819250762">"മൊബൈൽ ഡാറ്റ"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"വൈഫൈ ഓഫാണ്"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index e86dc64..331e9b7 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -101,10 +101,12 @@
     <string name="camera_label" msgid="7261107956054836961">"камер нээх"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Шинэ ажиллах талбарыг сонгоно уу"</string>
     <string name="cancel" msgid="6442560571259935130">"Цуцлах"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Тусламжийн зурвасын хэсэг"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Баталгаажуулах"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Хурууны хээ мэдрэгчид хүрэх"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Хурууны хээний дүрс тэмдэг"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Аппын дүрс тэмдэг"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Туслах зурвасын хэсэг"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Таныг хайж байна…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Царайны дүрс тэмдэг"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Тохиромжтой өсгөх товч."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Жижгээс том дэлгэцрүү өсгөх."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth холбогдсон."</string>
@@ -821,9 +823,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Хадгалах сан"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Заавар"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Шуурхай апп"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Шуурхай аппыг суулгах шаардлагагүй."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g>-г ажиллуулж байна"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Аппыг суулгахгүйгээр нээсэн."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Аппыг суулгахгүйгээр нээсэн. Нэмэлт мэдээлэл авахын тулд товшино уу."</string>
     <string name="app_info" msgid="6856026610594615344">"Апп-н мэдээлэл"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Хөтчид очих"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Вэбэд очих"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Мобайл дата"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi унтраалттай байна"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index a9f9af4..33761ca 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"कॅमेरा उघडा"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"नवीन कार्य लेआउट निवडा"</string>
     <string name="cancel" msgid="6442560571259935130">"रद्द करा"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"मदत मेसेज परिसर"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"खात्री करा"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"फिंगरप्रिंट सेन्सरला स्पर्श करा"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"फिंगरप्रिंट आयकन"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"अॅप्लिकेशन आयकन"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"मदत मेसेज क्षेत्र"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"तुमच्यासाठी शोधत आहे…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"चेहरा आयकन"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"सुसंगतता झूम बटण."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"लहानपासून मोठ्‍या स्‍क्रीनवर झूम करा."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ब्लूटूथ कनेक्‍ट केले."</string>
@@ -823,9 +825,14 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"स्टोरेज"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"सूचना"</string>
     <string name="instant_apps" msgid="6647570248119804907">"इन्सटंट अ‍ॅप्स"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"इन्सटंट अॅप्सना स्थापनेची आवश्यकता नसते."</string>
+    <!-- no translation found for instant_apps_title (8738419517367449783) -->
+    <skip />
+    <!-- no translation found for instant_apps_message (1183313016396018086) -->
+    <skip />
+    <!-- no translation found for instant_apps_message_with_help (6179830437630729747) -->
+    <skip />
     <string name="app_info" msgid="6856026610594615344">"अॅप माहिती"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"ब्राउझरवर जा"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"वेबवर जा"</string>
     <string name="mobile_data" msgid="7094582042819250762">"मोबाइल डेटा"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"वाय-फाय बंद आहे"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 6ec7889..d6a71ef 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"buka kamera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Pilih reka letak tugas baharu"</string>
     <string name="cancel" msgid="6442560571259935130">"Batal"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Bahagian mesej bantuan"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Sahkan"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Sentuh penderia cap jari"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikon cap jari"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Ikon aplikasi"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Bahagian mesej bantuan"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Mencari anda…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ikon wajah"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Butang zum keserasian."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Skrin zum lebih kecil kepada lebih besar."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth disambungkan."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Storan"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Pembayang"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Apl Segera"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Apl segera tidak memerlukan pemasangan."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> sedang berjalan"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Apl dibuka tanpa dipasang."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Apl dibuka tanpa dipasang. Ketik untuk mengetahui lebih lanjut."</string>
     <string name="app_info" msgid="6856026610594615344">"Maklumat apl"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Pergi ke penyemak imbas"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Pergi ke web"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Data mudah alih"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi dimatikan"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 7afb3b9..2a6e3c2 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"ကင်မရာ ဖွင့်ရန်"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"အလုပ်သစ်စီစဥ်မှုကို ရွေးပါ။"</string>
     <string name="cancel" msgid="6442560571259935130">"မလုပ်တော့"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"အကူအညီမက်ဆေ့ဂျ် နေရာ"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"အတည်ပြုပါ"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"လက်ဗွေအာရုံခံကိရိယာကို တို့ပါ"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"လက်ဗွေ သင်္ကေတ"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"အပလီကေးရှင်း သင်္ကေတ"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"အကူအညီမက်ဆေ့ဂျ် နေရာ"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"သင့်ကို ရှာဖွေနေသည်…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"မျက်နှာသင်္ကေတ"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"အံဝင်ခွင်ကျ ဇူးမ်ခလုတ်"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ဖန်သားပြင်ပေါ်တွင် အသေးမှအကြီးသို့ ဇူးမ်ဆွဲခြင်း"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ဘလူးတုသ်ချိတ်ဆက်ထားမှု"</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"သိုလှောင်မှုများ"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"အရိပ်အမြွက်များ"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"ချက်ခြင်းသုံးအက်ပ်များကို ထည့်သွင်းစရာမလိုပါ။"</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> လုပ်ဆောင်နေသည်"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"အက်ပ်ကိုမထည့်သွင်းဘဲ ဖွင့်ထားသည်။"</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"အက်ပ်ကိုမထည့်သွင်းဘဲ ဖွင့်ထားသည်။ ပိုမိုလေ့လာရန် တို့ပါ။"</string>
     <string name="app_info" msgid="6856026610594615344">"အက်ပ်အချက်အလက်"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"ဘရောင်ဇာသို့ သွားပါ"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"ဝဘ်သို့ သွားရန်"</string>
     <string name="mobile_data" msgid="7094582042819250762">"မိုဘိုင်းဒေတာ"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> —<xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi ကို ပိတ်ထားသည်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index b817877..d90eba3 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"åpne kamera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Velg en ny utforming for oppgaver"</string>
     <string name="cancel" msgid="6442560571259935130">"Avbryt"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Område for hjelpemelding"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Bekreft"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Trykk på fingeravtrykkssensoren"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikon for fingeravtrykk"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Appikon"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Område for hjelpemelding"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Ser etter deg …"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ansiktikon"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Zoomknapp for kompatibilitet."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom fra mindre til større skjerm."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth er tilkoblet."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Lagring"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Hint"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Du trenger ikke å installere instant-apper."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> kjører"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Appen ble åpnet uten at den ble installert."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Appen ble åpnet uten at den ble installert. Trykk for å finne ut mer."</string>
     <string name="app_info" msgid="6856026610594615344">"Info om appen"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Gå til nettleser"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Gå til nettstedet"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Mobildata"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi er av"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 6cc405f..4e3cddd 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"क्यामेरा खोल्नुहोस्"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"नयाँ कार्य लेआउट चयन गर्नुहोस्"</string>
     <string name="cancel" msgid="6442560571259935130">"रद्द गर्नुहोस्"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"मद्दतसम्बन्धी सन्देशको क्षेत्र"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"पुष्टि गर्नुहोस्"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"फिंगरप्रिन्ट सेन्सरमा छुनुहोस्‌"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"फिंगरप्रिन्ट जनाउने आइकन"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"अनुप्रयोग जनाउने आइकन"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"मद्दतसम्बन्धी सन्देशको क्षेत्र"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"तपाईंलाई खोज्दै…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"अनुहारको आइकन"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"मिलाउने जुम बटन।"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"स्क्रिनलाई सानोबाट ठूलो पार्नुहोस्।"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ब्लुटुथ जडान भयो।"</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"भण्डारण"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"सङ्केतहरू"</string>
     <string name="instant_apps" msgid="6647570248119804907">"तात्कालिक अनुप्रयोगहरू"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"तात्कालिक अनुप्रयोगहरूलाई स्थापना गर्नु पर्दैन|"</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> चलिरहेको छ"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"स्थापना नगरिकनै अनुप्रयोग खोलियो।"</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"स्थापना नगरिकनै अनुप्रयोग खोलियो। थप जान्न ट्याप गर्नुहोस्।"</string>
     <string name="app_info" msgid="6856026610594615344">"अनुप्रयोगका बारे जानकारी"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"ब्राउजरमा जानुहोस्"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"वेबमा जानुहोस्"</string>
     <string name="mobile_data" msgid="7094582042819250762">"मोबाइल डेटा"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi‑Fi निष्क्रिय छ"</string>
diff --git a/packages/SystemUI/res/values-night/styles.xml b/packages/SystemUI/res/values-night/styles.xml
new file mode 100644
index 0000000..3ab6b56
--- /dev/null
+++ b/packages/SystemUI/res/values-night/styles.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <style name="Theme.SystemUI.Dialog" parent="@android:style/Theme.DeviceDefault.Dialog" />
+
+    <style name="Theme.SystemUI.Dialog.Alert" parent="@*android:style/Theme.DeviceDefault.Dialog.Alert" />
+
+    <style name="Theme.SystemUI.Dialog.GlobalActions" parent="@android:style/Theme.DeviceDefault.NoActionBar.Fullscreen">
+        <item name="android:windowIsFloating">true</item>
+    </style>
+
+</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index e8c6f8d..9dda44e 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"camera openen"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Nieuwe taakindeling selecteren"</string>
     <string name="cancel" msgid="6442560571259935130">"Annuleren"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Gebied voor Help-berichten"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Bevestigen"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Raak de vingerafdruksensor aan"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Vingerafdrukpictogram"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"App-pictogram"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Gebied voor Help-berichten"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Jouw gezicht zoeken…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Gezichtspictogram"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Knop voor compatibiliteitszoom."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kleiner scherm uitzoomen naar groter scherm."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth-verbinding ingesteld."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Opslag"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Hints"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Instant-apps"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Instant-apps hoeven niet te worden geïnstalleerd."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> actief"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"App geopend zonder dat deze is geïnstalleerd."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"App geopend zonder dat deze is geïnstalleerd. Tik voor meer informatie."</string>
     <string name="app_info" msgid="6856026610594615344">"App-info"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Ga naar browser"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Ga naar internet"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Mobiele data"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wifi is uitgeschakeld"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 277181f..91c62bb 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"କ୍ୟାମେରା ଖୋଲନ୍ତୁ"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"ନୂଆ ଟାସ୍କ ଲେଆଉଟ୍‍ ଚୟନ କରନ୍ତୁ"</string>
     <string name="cancel" msgid="6442560571259935130">"କ୍ୟାନ୍ସଲ୍‍ କରନ୍ତୁ"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"ସାହାଯ୍ୟ ମେସେଜ୍ କ୍ଷେତ୍ର"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"ନିଶ୍ଚିତ କରନ୍ତୁ"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ସେନସର୍‌କୁ ଛୁଅଁନ୍ତୁ"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ଆଇକନ୍"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"ଆପ୍ଲିକେଶନ୍‌ ଆଇକନ୍‌"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"ହେଲ୍ପ ମେସେଜ୍ କ୍ଷେତ୍ର"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"ଆପଣଙ୍କୁ ଚିହ୍ନଟ କରୁଛି…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"ମୁହଁ ଆଇକନ୍"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"କମ୍ପାଟିବିଲିଟୀ ଜୁମ୍ ବଟନ୍।"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ଜୁମ୍ କରି ସ୍କ୍ରୀନ୍‌କୁ ଛୋଟରୁ ବଡ଼ କରନ୍ତୁ।"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ବ୍ଲୁ-ଟୂଥ୍‍‌ ସଂଯୋଗ କରାଯାଇଛି।"</string>
@@ -823,9 +825,14 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"ଷ୍ଟୋରେଜ୍‌"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"ହିଣ୍ଟ"</string>
     <string name="instant_apps" msgid="6647570248119804907">"ଇନଷ୍ଟାଣ୍ଟ ଆପ୍‌"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"ଇନଷ୍ଟାଣ୍ଟ ଆପ୍‌ ଇନଷ୍ଟଲ୍‍ କରିବାର ଆବଶ୍ୟକତା ନାହିଁ"</string>
+    <!-- no translation found for instant_apps_title (8738419517367449783) -->
+    <skip />
+    <!-- no translation found for instant_apps_message (1183313016396018086) -->
+    <skip />
+    <!-- no translation found for instant_apps_message_with_help (6179830437630729747) -->
+    <skip />
     <string name="app_info" msgid="6856026610594615344">"ଆପ୍‍ ସୂଚନା"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"ବ୍ରାଉଜର୍‌କୁ ଯାଆନ୍ତୁ"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"ୱେବକୁ ଯାଆନ୍ତୁ"</string>
     <string name="mobile_data" msgid="7094582042819250762">"ମୋବାଇଲ୍‌ ଡାଟା"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"ୱାଇ-ଫାଇ ଅଫ୍‍ ଅଛି"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 6509871..96fb641 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"ਕੈਮਰਾ ਖੋਲ੍ਹੋ"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"ਨਵਾਂ ਕੰਮ ਲੇਆਉਟ ਚੁਣੋ"</string>
     <string name="cancel" msgid="6442560571259935130">"ਰੱਦ ਕਰੋ"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"ਮਦਦ ਸੁਨੇਹਾ ਖੇਤਰ"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"ਪੁਸ਼ਟੀ ਕਰੋ"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਨੂੰ ਸਪੱਰਸ਼ ਕਰੋ"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਦਾ ਪ੍ਰਤੀਕ"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"ਐਪਲੀਕੇਸ਼ਨ ਦਾ ਪ੍ਰਤੀਕ"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"ਮਦਦ ਸੁਨੇਹਾ ਖੇਤਰ"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"ਤੁਹਾਡੀ ਪਛਾਣ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"ਚਿਹਰਾ ਪ੍ਰਤੀਕ"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ਅਨੁਰੂਪਤਾ ਜ਼ੂਮ ਬਟਨ।"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ਵੱਡੀ ਸਕ੍ਰੀਨ ਤੇ ਛੋਟਾ ਜ਼ੂਮ ਕਰੋ।"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth ਕਨੈਕਟ ਕੀਤੀ।"</string>
@@ -344,7 +346,7 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ਸੀਮਾ"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ਚਿਤਾਵਨੀ"</string>
     <string name="quick_settings_work_mode_label" msgid="7608026833638817218">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ"</string>
-    <string name="quick_settings_night_display_label" msgid="3577098011487644395">"ਰਾਤਰੀ ਲਾਈਟ"</string>
+    <string name="quick_settings_night_display_label" msgid="3577098011487644395">"ਰਾਤ ਦੀ ਰੋਸ਼ਨੀ"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"ਸੂਰਜ ਛਿਪਣ \'ਤੇ ਚਾਲੂ"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"ਸੂਰਜ ਚੜ੍ਹਨ ਤੱਕ"</string>
     <string name="quick_settings_night_secondary_label_on_at" msgid="6256314040368487637">"<xliff:g id="TIME">%s</xliff:g> ਵਜੇ ਚਾਲੂ"</string>
@@ -823,9 +825,14 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"ਸਟੋਰੇਜ"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"ਸੰਕੇਤ"</string>
     <string name="instant_apps" msgid="6647570248119804907">"ਤਤਕਾਲ ਐਪਾਂ"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"ਤਤਕਾਲ ਐਪਾਂ ਨੂੰ ਸਥਾਪਨਾ ਦੀ ਲੋੜ ਨਹੀਂ ਹੈ।"</string>
+    <!-- no translation found for instant_apps_title (8738419517367449783) -->
+    <skip />
+    <!-- no translation found for instant_apps_message (1183313016396018086) -->
+    <skip />
+    <!-- no translation found for instant_apps_message_with_help (6179830437630729747) -->
+    <skip />
     <string name="app_info" msgid="6856026610594615344">"ਐਪ ਜਾਣਕਾਰੀ"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"ਬ੍ਰਾਊਜ਼ਰ \'ਤੇ ਜਾਓ"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"ਵੈੱਬ \'ਤੇ ਜਾਓ"</string>
     <string name="mobile_data" msgid="7094582042819250762">"ਮੋਬਾਈਲ ਡਾਟਾ"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"ਵਾਈ-ਫਾਈ ਬੰਦ ਹੈ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 2959a8d..28d24bf 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -105,10 +105,12 @@
     <string name="camera_label" msgid="7261107956054836961">"otwórz aparat"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Wybierz nowy układ zadań"</string>
     <string name="cancel" msgid="6442560571259935130">"Anuluj"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Obszar komunikatu pomocy"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Potwierdź"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Dotknij czytnika linii papilarnych"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikona odcisku palca"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Ikona aplikacji"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Obszar komunikatu pomocy"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Szukam Cię…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ikona twarzy"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Przycisk powiększenia na potrzeby zgodności."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Powiększa mniejszy ekran do większego."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth połączony."</string>
@@ -835,9 +837,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Pamięć wewnętrzna"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Wskazówki"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Aplikacje błyskawiczne"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Aplikacji błyskawicznych nie trzeba instalować."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"Aplikacja <xliff:g id="APP">%1$s</xliff:g> działa"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Aplikacja została otwarta bez zainstalowania."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Aplikacja została otwarta bez zainstalowania. Kliknij, by dowiedzieć się więcej."</string>
     <string name="app_info" msgid="6856026610594615344">"O aplikacji"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Otwórz przeglądarkę"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Wejdź na stronę internetową"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Komórkowa transmisja danych"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi jest wyłączone"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index ba50c13..ab0f5f2 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"abrir câmera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Selecionar novo layout da tarefa"</string>
     <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Área da mensagem de ajuda"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirmar"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Toque no sensor de impressão digital"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ícone de impressão digital"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Ícone do app"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Área da mensagem de ajuda"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Procurando você…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ícone facial"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botão de zoom da compatibilidade."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Aumentar a tela com zoom."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth conectado."</string>
@@ -825,9 +827,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Armazenamento"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Dicas"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Os Instant Apps não requerem instalação."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> em execução"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"O app é aberto sem precisar ser instalado."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"O app é aberto sem precisar ser instalado. Toque para saber mais."</string>
     <string name="app_info" msgid="6856026610594615344">"Informações do app"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Abrir o navegador"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Acessar a Web"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Dados móveis"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"O Wi-Fi está desativado"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index a03dba2..fb0675a 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"abrir câmara"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Selecionar novo esquema de tarefa"</string>
     <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Área da mensagem de ajuda"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirmar"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Toque no sensor de impressões digitais."</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ícone de impressão digital"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Ícone de aplicação"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Área da mensagem de ajuda"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"À sua procura…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ícone de rosto"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botão zoom de compatibilidade."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom menor para ecrã maior."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth ligado."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Armazenamento"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Sugestões"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Aplicações instantâneas"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"As Aplicações instantâneas não requerem instalação."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> em execução"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"A aplicação é aberta sem ser instalada."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"A aplicação é aberta sem ser instalada. Toque para saber mais."</string>
     <string name="app_info" msgid="6856026610594615344">"Info. da aplicação"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Ir para o navegador"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Aceder à Web"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Dados móveis"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi desativado"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index ba50c13..ab0f5f2 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"abrir câmera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Selecionar novo layout da tarefa"</string>
     <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Área da mensagem de ajuda"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirmar"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Toque no sensor de impressão digital"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ícone de impressão digital"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Ícone do app"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Área da mensagem de ajuda"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Procurando você…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ícone facial"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botão de zoom da compatibilidade."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Aumentar a tela com zoom."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth conectado."</string>
@@ -825,9 +827,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Armazenamento"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Dicas"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Os Instant Apps não requerem instalação."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> em execução"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"O app é aberto sem precisar ser instalado."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"O app é aberto sem precisar ser instalado. Toque para saber mais."</string>
     <string name="app_info" msgid="6856026610594615344">"Informações do app"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Abrir o navegador"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Acessar a Web"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Dados móveis"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"O Wi-Fi está desativado"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 149803b..9b5f5e1 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -104,10 +104,12 @@
     <string name="camera_label" msgid="7261107956054836961">"deschideți camera foto"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Selectați noul aspect pentru activitate"</string>
     <string name="cancel" msgid="6442560571259935130">"Anulați"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Zona mesajelor de ajutor"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Confirmați"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Atingeți senzorul de amprente"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Pictograma amprentă"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Pictograma aplicației"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Zona mesajelor de ajutor"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Vă căutăm…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Pictograma chip"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Buton zoom pentru compatibilitate."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Faceți zoom de la o imagine mai mică la una mai mare."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Conectat prin Bluetooth."</string>
@@ -831,9 +833,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Stocare"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Indicii"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Aplicații instantanee"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Aplicațiile instantanee nu necesită instalare."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> rulează"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Aplicația a fost deschisă fără a fi instalată."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Aplicația a fost deschisă fără a fi instalată. Atingeți pentru a afla mai multe."</string>
     <string name="app_info" msgid="6856026610594615344">"Informații despre aplicație"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Accesați browserul"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Accesați pe web"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Date mobile"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Conexiunea Wi-Fi este dezactivată"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 7a756cd..8069317 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -105,10 +105,12 @@
     <string name="camera_label" msgid="7261107956054836961">"Открыть камеру."</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Выберите другой макет"</string>
     <string name="cancel" msgid="6442560571259935130">"Отмена"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Справочное сообщение"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Подтвердить"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Прикоснитесь к сканеру отпечатков пальцев."</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Значок отпечатка пальца"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Значок приложения"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Справочное сообщение"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Поиск лица…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Значок лица"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Кнопка масштабирования (режим совместимости)"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Уменьшение изображения для увеличения свободного места на экране."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth-соединение установлено."</string>
@@ -837,9 +839,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Хранилище"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Подсказки"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Приложения с мгновенным запуском"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Приложения с мгновенным запуском не требуется устанавливать."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> уже здесь!"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Приложение готово к работе, установка не требуется."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Приложение готово к работе, установка не требуется. Нажмите, чтобы узнать больше."</string>
     <string name="app_info" msgid="6856026610594615344">"О приложении"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Перейти в браузер"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Перейти в браузер"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Моб. Интернет"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Модуль Wi-Fi отключен"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index e29aeda..8802833 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"කැමරාව විවෘත කරන්න"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"නව කාර්යය සැකැස්ම තෝරන්න"</string>
     <string name="cancel" msgid="6442560571259935130">"අවලංගු කරන්න"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"උදවු පණිවිඩ ප්‍රදේශය"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"තහවුරු කරන්න"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"ඇඟිලි සලකුණු සංවේදකය ස්පර්ශ කරන්න"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"ඇඟිලි සලකුණු නිරූපකය"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"යෙදුම් නිරූපකය"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"උදවු පණිවිඩ ප්‍රදේශය"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"ඔබව සොයමින්…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"මුහුණ නිරූපකය"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ගැළපෙන විශාලන බොත්තම."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"විශාල තිරය වෙත කුඩාව විශාලනය කරන්න."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"බ්ලූටූත් සම්බන්ධිතයි."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"ගබඩාව"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"ඉඟි"</string>
     <string name="instant_apps" msgid="6647570248119804907">"ක්ෂණික යෙදුම්"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"ක්ෂණික යෙදුම් ස්ථාපනය කිරීම අවශ්‍ය නොවේ."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> ධාවනය වෙමින්"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"ස්ථාපනය නොකර යෙදුම විවෘත කර ඇත."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"ස්ථාපනය නොකර යෙදුම විවෘත කර ඇත. තව දැන ගැනීමට තට්ටු කරන්න."</string>
     <string name="app_info" msgid="6856026610594615344">"යෙදුම් තොරතුරු"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"බ්‍රවුසරය වෙත යන්න"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"වෙබය වෙත යන්න"</string>
     <string name="mobile_data" msgid="7094582042819250762">"ජංගම දත්ත"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi ක්‍රියා විරහිතයි"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 8193e3f..233a81b 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -105,10 +105,12 @@
     <string name="camera_label" msgid="7261107956054836961">"spustiť fotoaparát"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Vyberte nové rozloženie úlohy"</string>
     <string name="cancel" msgid="6442560571259935130">"Zrušiť"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Oblasť správy pomocníka"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Potvrdiť"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Klepnite na senzor odtlačkov prstov"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikona odtlačku prsta"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Ikona aplikácie"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Oblasť chybového hlásenia"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Hľadáme vás…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ikona tváre"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Tlačidlo úpravy veľkosti z dôvodu kompatibility."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zväčšiť menší obrázok na väčšiu obrazovku."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth pripojené."</string>
@@ -837,9 +839,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Úložisko"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Tipy"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Okamžité aplikácie"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Okamžité aplikácie nevyžadujú inštaláciu."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"Aplikácia <xliff:g id="APP">%1$s</xliff:g> je spustená"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Aplikácia bola otvorená bez inštalácie."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Aplikácia bola otvorená bez inštalácie. Klepnutím zobrazíte ďalšie informácie."</string>
     <string name="app_info" msgid="6856026610594615344">"Info o aplikácii"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Otvoriť prehliadač"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Prejsť na internet"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Mobilné dáta"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Pripojenie Wi‑Fi je vypnuté"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 7169441..c7e661a 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -105,10 +105,12 @@
     <string name="camera_label" msgid="7261107956054836961">"odpri fotoaparat"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Izberite novo postavitev opravil"</string>
     <string name="cancel" msgid="6442560571259935130">"Prekliči"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Območje sporočila pomoči"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Potrdite"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Dotaknite se tipala prstnih odtisov"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikona prstnih odtisov"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Ikona aplikacije"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Območje sporočila pomoči"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Preverjanje vašega obraza …"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ikona obraza"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Gumb povečave za združljivost."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Povečava manjšega na večji zaslon."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Povezava Bluetooth vzpostavljena."</string>
@@ -837,9 +839,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Shramba"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Namigi"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Nenamestljive aplikacije"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Nenamestljivih aplikacij ni treba namestiti."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> se izvaja"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Aplikacija je odprta brez namestitve."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Aplikacija je odprta brez namestitve. Dotaknite se, če želite izvedeti več."</string>
     <string name="app_info" msgid="6856026610594615344">"Podatki o aplikaciji"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Odpri brskalnik"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Pojdi v splet"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Mobilni podatki"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi je izklopljen"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index f2903ef..f4d3d2a 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"hap kamerën"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Zgjidh strukturën e re të detyrës"</string>
     <string name="cancel" msgid="6442560571259935130">"Anulo"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Zona e mesazhit të ndihmës"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Konfirmo"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Prek sensorin e gjurmës së gishtit"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikona e gjurmës së gishtit"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Ikona e aplikacionit"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Zona e mesazhit të ndihmës"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Po të kërkojmë…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ikona e fytyrës"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Butoni i zmadhimit të pajtueshmërisë."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zmadho nga një ekran i vogël në të madh."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Pajisja është lidhur me \"bluetooth\"."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Hapësira ruajtëse"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Sugjerimet"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Aplikacionet e çastit"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Aplikacionet e çastit nuk kërkojnë instalim."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"Po ekzekutohet <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Aplikacioni u hap pa u instaluar."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Aplikacioni u hap pa u instaluar. Trokit për të mësuar më shumë."</string>
     <string name="app_info" msgid="6856026610594615344">"Informacioni mbi aplikacionin"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Shko te shfletuesi"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Shko në ueb"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Të dhënat celulare"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> - <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi është joaktiv"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index e77b080..5825231 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -104,10 +104,12 @@
     <string name="camera_label" msgid="7261107956054836961">"отвори камеру"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Изабери нови распоред задатака"</string>
     <string name="cancel" msgid="6442560571259935130">"Откажи"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Област поруке за помоћ"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Потврди"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Додирните сензор за отисак прста"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Икона отиска прста"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Икона апликације"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Област поруке за помоћ"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Тражимо вас…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Икона лица"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Дугме Зум компатибилности."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Зумирање са мањег на већи екран."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth је прикључен."</string>
@@ -829,9 +831,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Меморијски простор"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Савети"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Инстант апликације"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Инстант апликације не захтевају инсталацију."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"Апликација <xliff:g id="APP">%1$s</xliff:g> је покренута"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Апликација се отворила без инсталирања."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Апликација се отворила без инсталирања. Додирните да бисте сазнали више."</string>
     <string name="app_info" msgid="6856026610594615344">"Информације о апликацији"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Иди на прегледач"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Иди на веб"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Мобилни подаци"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi је искључен"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index ccc498e..7040ec2 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"öppna kameran"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Välj en ny layout för uppgiften"</string>
     <string name="cancel" msgid="6442560571259935130">"Avbryt"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Område för hjälpmeddelande"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Bekräfta"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Tryck på fingeravtryckssensorn"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikon för fingeravtryck"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Appikon"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Område för hjälpmeddelande"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Håller utkik efter dig …"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Ansiktsikon"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Knapp för kompatibilitetszoom."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zooma mindre skärm till större."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth ansluten."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Lagring"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Tips"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Snabbappar"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Snabbappar behöver inte installeras."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> körs"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Appen öppnades utan installation."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Appen öppnades utan installation. Tryck om du vill veta mer."</string>
     <string name="app_info" msgid="6856026610594615344">"Info om appen"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Öppna webbläsaren"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Öppna webbplatsen"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Mobildata"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi är inaktiverat"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 83e9997..0633e8a 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"fungua kamera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Chagua muundo mpya wa kazi"</string>
     <string name="cancel" msgid="6442560571259935130">"Ghairi"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Sehemu ya ujumbe wa usaidizi"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Thibitisha"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Gusa kitambua alama ya kidole"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Aikoni ya alama ya kidole"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Aikoni ya programu"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Sehemu ya ujumbe wa usaidizi"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Inakutafuta…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Aikoni ya uso"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Kichupo cha kukuza kwa utangamanifu"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kuza kidogo kwa skrini kubwa."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth imeunganishwa."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Hifadhi"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Vidokezo"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Programu Zinazofunguka Papo Hapo"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Huhitaji kusakinisha programu zinazofunguka papo hapo."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> inaendelea kutumika"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Programu inafunguka bila kusakinishwa."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Programu inafunguka bila kusakinishwa. Gusa ili upate maelezo zaidi."</string>
     <string name="app_info" msgid="6856026610594615344">"Maelezo ya programu"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Tumia kivinjari"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Nenda kwenye wavuti"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Data ya simu"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g><xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi imezimwa"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 6f06ab5..469e797 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"கேமராவைத் திற"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"புதிய பணி தளவமைப்பைத் தேர்ந்தெடுக்கவும்"</string>
     <string name="cancel" msgid="6442560571259935130">"ரத்துசெய்"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"உதவிச் செய்திக்கான பகுதி"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"உறுதிப்படுத்துக"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"கைரேகை உணர்வியைத் தொடவும்"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"கைரேகை ஐகான்"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"பயன்பாட்டு ஐகான்"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"உதவிச் செய்திக்கான பகுதி"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"உங்கள் முகத்தைத் தேடுகிறது…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"முக ஐகான்"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"பொருந்துமாறு அளவை மாற்றும் பொத்தான்."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"சிறியதிலிருந்து பெரிய திரைக்கு அளவை மாற்றும்."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"புளூடூத் இணைக்கப்பட்டது."</string>
@@ -344,9 +346,9 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> வரம்பு"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> எச்சரிக்கை"</string>
     <string name="quick_settings_work_mode_label" msgid="7608026833638817218">"பணி விவரம்"</string>
-    <string name="quick_settings_night_display_label" msgid="3577098011487644395">"இரவு ஒளி"</string>
+    <string name="quick_settings_night_display_label" msgid="3577098011487644395">"நைட் லைட்"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"மாலையில் ஆன் செய்"</string>
-    <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"சூரிய உதயம் வரை"</string>
+    <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"காலை வரை"</string>
     <string name="quick_settings_night_secondary_label_on_at" msgid="6256314040368487637">"<xliff:g id="TIME">%s</xliff:g>க்கு ஆன் செய்"</string>
     <string name="quick_settings_secondary_label_until" msgid="2749196569462600150">"<xliff:g id="TIME">%s</xliff:g> வரை"</string>
     <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
@@ -823,9 +825,14 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"சேமிப்பிடம்"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"குறிப்புகள்"</string>
     <string name="instant_apps" msgid="6647570248119804907">"இன்ஸ்டண்ட் ஆப்ஸ்"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"இன்ஸ்டண்ட் பயன்பாடுகளுக்கு நிறுவல் தேவையில்லை."</string>
+    <!-- no translation found for instant_apps_title (8738419517367449783) -->
+    <skip />
+    <!-- no translation found for instant_apps_message (1183313016396018086) -->
+    <skip />
+    <!-- no translation found for instant_apps_message_with_help (6179830437630729747) -->
+    <skip />
     <string name="app_info" msgid="6856026610594615344">"பயன்பாட்டுத் தகவல்"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"உலாவிக்குச் செல்"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"இணையத்திற்குச் செல்"</string>
     <string name="mobile_data" msgid="7094582042819250762">"மொபைல் டேட்டா"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"வைஃபை முடக்கத்தில் உள்ளது"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 7c09699..5d869f1 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"కెమెరాను తెరువు"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"కొత్త విధి లేఅవుట్‌ను ఎంచుకోండి"</string>
     <string name="cancel" msgid="6442560571259935130">"రద్దు చేయి"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"సహాయ సందేశ ప్రాంతం"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"నిర్ధారించు"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"వేలిముద్ర సెన్సార్‌ను తాకండి"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"వేలిముద్ర చిహ్నం"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"అప్లికేషన్ చిహ్నం"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"సహాయ సందేశ ప్రాంతం"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"మీ కోసం చూస్తోంది…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"ముఖ చిహ్నం"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"అనుకూలత జూమ్ బటన్."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"చిన్న స్క్రీన్ నుండి పెద్దదానికి జూమ్ చేయండి."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"బ్లూటూత్ కనెక్ట్ చేయబడింది."</string>
@@ -823,9 +825,14 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"నిల్వ"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"సూచనలు"</string>
     <string name="instant_apps" msgid="6647570248119804907">"తక్షణ యాప్‌లు"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"తక్షణ అనువర్తనాలకు ఇన్‌స్టాలేషన్ అవసరం లేదు."</string>
+    <!-- no translation found for instant_apps_title (8738419517367449783) -->
+    <skip />
+    <!-- no translation found for instant_apps_message (1183313016396018086) -->
+    <skip />
+    <!-- no translation found for instant_apps_message_with_help (6179830437630729747) -->
+    <skip />
     <string name="app_info" msgid="6856026610594615344">"యాప్ సమాచారం"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"బ్రౌజర్‌కు వెళ్లండి"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"వెబ్‌కు వెళ్లు"</string>
     <string name="mobile_data" msgid="7094582042819250762">"మొబైల్ డేటా"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi ఆఫ్‌లో ఉంది"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 1d59868..408c5a0 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"เปิดกล้อง"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"เลือกรูปแบบงานใหม่"</string>
     <string name="cancel" msgid="6442560571259935130">"ยกเลิก"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"พื้นที่ข้อความช่วยเหลือ"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"ยืนยัน"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"แตะเซ็นเซอร์ลายนิ้วมือ"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"ไอคอนลายนิ้วมือ"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"ไอคอนแอปพลิเคชัน"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"พื้นที่ข้อความช่วยเหลือ"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"กำลังหาใบหน้าคุณ…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"ไอคอนใบหน้า"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ปุ่มซูมที่ใช้งานร่วมกันได้"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ซูมหน้าจอให้มีขนาดใหญ่ขึ้น"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"เชื่อมต่อบลูทูธแล้ว"</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"พื้นที่เก็บข้อมูล"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"คำแนะนำ"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Instant App"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Instant Apps ไม่ต้องใช้การติดตั้ง"</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> ทำงานอยู่"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"เปิดแอปได้โดยไม่ต้องติดตั้ง"</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"เปิดแอปได้โดยไม่ต้องติดตั้ง แตะเพื่อดูข้อมูลเพิ่มเติม"</string>
     <string name="app_info" msgid="6856026610594615344">"ข้อมูลแอป"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"ไปที่เบราว์เซอร์"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"ไปที่เว็บ"</string>
     <string name="mobile_data" msgid="7094582042819250762">"เน็ตมือถือ"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi ปิดอยู่"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 013acd4..8da4946 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"buksan ang camera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Pumili ng bagong layout ng gawain"</string>
     <string name="cancel" msgid="6442560571259935130">"Kanselahin"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Lugar ng mensahe ng tulong"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Kumpirmahin"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Pindutin ang fingerprint sensor"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Icon ng fingerprint"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Icon ng application"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Lugar ng mensahe ng tulong"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Hinahanap ka…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Face icon"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Button ng zoom ng pagiging tugma."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Mag-zoom nang mas maliit sa mas malaking screen."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Nakakonekta ang Bluetooth."</string>
@@ -346,7 +348,7 @@
     <string name="quick_settings_work_mode_label" msgid="7608026833638817218">"Profile sa trabaho"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Night Light"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"Mao-on sa sunset"</string>
-    <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"Hanggang mag-umaga"</string>
+    <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"Hanggang sunrise"</string>
     <string name="quick_settings_night_secondary_label_on_at" msgid="6256314040368487637">"Mao-on sa ganap na <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_secondary_label_until" msgid="2749196569462600150">"Hanggang <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Storage"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Mga Hint"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Instant Apps"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Hindi kailangang i-install ang mga instant na app."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"Tumatakbo ang <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Nabuksan ang app nang hindi ini-install."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Nabuksan ang app nang hindi ini-install. I-tap para matuto pa."</string>
     <string name="app_info" msgid="6856026610594615344">"Impormasyon ng app"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Pumunta sa browser"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Pumunta sa web"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Mobile data"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Naka-off ang Wi-Fi"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 9030113..de8ed9d 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"kamerayı aç"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Yeni görev düzenini seçin"</string>
     <string name="cancel" msgid="6442560571259935130">"İptal"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Yardım mesajı alanı"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Onaylayın"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Parmak izi sensörüne dokunun"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Parmak izi simgesi"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Uygulama simgesi"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Yardım mesajı alanı"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Yüzünüz tanınmaya çalışılıyor…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Yüz simgesi"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Uyumluluk zum düğmesi."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Daha büyük ekrana daha küçük yakınlaştır."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth bağlandı."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Depolama alanı"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"İpuçları"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Hazır Uygulamalar"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Hazır uygulamaların yüklenmesi gerekmez."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> çalışıyor"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Uygulama yüklenmeden açıldı."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Uygulama yüklenmeden açıldı. Daha fazla bilgi için dokunun."</string>
     <string name="app_info" msgid="6856026610594615344">"Uygulama bilgileri"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Tarayıcıya git"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Web\'e git"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Mobil veriler"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Kablosuz bağlantı kapalı"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index cf21c0f..6c2e661 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -105,10 +105,12 @@
     <string name="camera_label" msgid="7261107956054836961">"відкрити камеру"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Виберіть новий макет завдання"</string>
     <string name="cancel" msgid="6442560571259935130">"Скасувати"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Область довідкового повідомлення"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Підтвердити"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Торкніться сканера відбитків пальців"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Значок відбитка пальця"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Значок додатка"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Область довідкового повідомлення"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Пошук обличчя…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Значок обличчя"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Кнопка масштабування сумісності."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Збільшення екрана."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth під’єднано."</string>
@@ -837,9 +839,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Пам’ять"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Поради"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Додатки з миттєвим запуском"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Додатки з миттєвим запуском не потрібно встановлювати."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> працює"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Додаток відкрито без встановлення."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Додаток відкрито без встановлення. Торкніться, щоб дізнатися більше."</string>
     <string name="app_info" msgid="6856026610594615344">"Про додаток"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Веб-переглядач"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Перейти на веб-сайт"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Мобільний трафік"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi вимкнено"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index d2ee8c7..88391b0 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"کیمرا کھولیں"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"نئے کام کا لے آؤٹ منتخب کریں"</string>
     <string name="cancel" msgid="6442560571259935130">"منسوخ کریں"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"امدادی پیغام کا علاقہ"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"تصدیق کریں"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"فنگر پرنٹ سینسر پر ٹچ کریں"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"فنگر پرنٹ آئیکن"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"ایپلیکیشن کا آئیکن"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"امدادی پیغام کا علاقہ"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"آپ کے لیے تلاش کیا جا رہا ہے…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"چہرے کا آئیکن"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"مطابقت پذیری زوم بٹن۔"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"چھوٹی سے بڑی اسکرین پر زوم کریں۔"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"بلوٹوتھ مربوط ہے۔"</string>
@@ -823,9 +825,14 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"اسٹوریج"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"اشارات"</string>
     <string name="instant_apps" msgid="6647570248119804907">"فوری ایپس"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"فوری ایپس کو انسٹالیشن کی ضرورت نہیں ہے۔"</string>
+    <!-- no translation found for instant_apps_title (8738419517367449783) -->
+    <skip />
+    <!-- no translation found for instant_apps_message (1183313016396018086) -->
+    <skip />
+    <!-- no translation found for instant_apps_message_with_help (6179830437630729747) -->
+    <skip />
     <string name="app_info" msgid="6856026610594615344">"ایپ کی معلومات"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"براؤزر پر جائیں"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"ویب پر جائیں"</string>
     <string name="mobile_data" msgid="7094582042819250762">"موبائل ڈیٹا"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"‏Wi-Fi آف ہے"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 2c45ab8..37d31c2 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"kamerani ochish"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Yangi vazifa tartibini tanlash"</string>
     <string name="cancel" msgid="6442560571259935130">"Bekor qilish"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Yordam xabari"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"OK"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Barmoq izi skaneriga tegining"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Barmoq izi belgisi"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Ilova belgisi"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Yordam xabari"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Yuzingiz tekshirilmoqda…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Yuz belgisi"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Kattalashtirish tugmasi mosligi."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kattaroq ekran uchun kichikroqni kattalashtirish."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth ulandi."</string>
@@ -825,9 +827,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Xotira"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Maslahatlar"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Darhol ochiladigan ilovalar"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Darhol ochiladigan ilovalarni o‘rnatish shart emas."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> ishlamoqda"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Ilova o‘rnatilmasdan ochildi."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Ilova o‘rnatilmasdan ochildi. Batafsil axborot oolish uchun bu yerga bosing."</string>
     <string name="app_info" msgid="6856026610594615344">"Ilova haqida"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Brauzerni ochish"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Brauzerga o‘tish"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Mobil internet"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi o‘chiq"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 8c5e10d..f476790 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"mở máy ảnh"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Chọn bố cục tác vụ mới"</string>
     <string name="cancel" msgid="6442560571259935130">"Hủy"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Vùng thông báo trợ giúp"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Xác nhận"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Chạm vào cảm biến vân tay"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Biểu tượng vân tay"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Biểu tượng ứng dụng"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Vùng thông báo trợ giúp"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Đang tìm kiếm bạn…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Biểu tượng khuôn mặt"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Nút thu phóng khả năng tương thích."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Thu phóng màn hình lớn hơn hoặc nhỏ hơn."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Đã kết nối bluetooth."</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Bộ nhớ"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Gợi ý"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Ứng dụng tức thì"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Ứng dụng tức thì không yêu cầu cài đặt."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> đang chạy"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Ứng dụng được mở mà không cần cài đặt."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Ứng dụng được mở mà không cần cài đặt. Nhấn để tìm hiểu thêm."</string>
     <string name="app_info" msgid="6856026610594615344">"Thông tin ứng dụng"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Đi tới trình duyệt"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Truy cập web"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Dữ liệu di động"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi tắt"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 6259bfd..aaa4c63 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"打开相机"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"选择新的任务布局"</string>
     <string name="cancel" msgid="6442560571259935130">"取消"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"帮助消息区域"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"确认"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"请触摸指纹传感器"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"指纹图标"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"应用图标"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"帮助消息区域"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"正在查找中…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"面孔图标"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"兼容性缩放按钮。"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"将小屏幕的图片放大在较大屏幕上显示。"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"蓝牙已连接。"</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"存储空间"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"提示"</string>
     <string name="instant_apps" msgid="6647570248119804907">"免安装应用"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"免安装应用无需安装就能使用。"</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"正在运行<xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"已打开免安装应用。"</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"已打开免安装应用。点按即可了解详情。"</string>
     <string name="app_info" msgid="6856026610594615344">"应用信息"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"转到浏览器"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"转到网页版"</string>
     <string name="mobile_data" msgid="7094582042819250762">"移动数据"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> - <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"WLAN 已关闭"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index aa19f4f..aad4b4f 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"開啟相機"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"選取新的工作版面配置"</string>
     <string name="cancel" msgid="6442560571259935130">"取消"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"說明訊息區域"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"確認"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"請輕觸指紋感應器"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"指紋圖示"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"應用程式圖示"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"說明訊息區域"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"正在搜尋您的臉孔…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"面孔圖示"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"相容性縮放按鈕。"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"將較小螢幕的畫面放大在較大螢幕上顯示。"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"藍牙連線已建立。"</string>
@@ -825,9 +827,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"儲存空間"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"提示"</string>
     <string name="instant_apps" msgid="6647570248119804907">"即時應用程式"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"即時應用程式無需安裝即可使用。"</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> 運作中"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"已開啟免安裝應用程式。"</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"已開啟免安裝應用程式。輕按即可瞭解詳情。"</string>
     <string name="app_info" msgid="6856026610594615344">"應用程式資料"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"前往瀏覽器"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"前往網頁版"</string>
     <string name="mobile_data" msgid="7094582042819250762">"流動數據"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> - <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi 已關閉"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 363c610..6b88545 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"開啟攝影機"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"選取新工作版面配置"</string>
     <string name="cancel" msgid="6442560571259935130">"取消"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"說明訊息區域"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"確認"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"請輕觸指紋感應器"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"指紋圖示"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"應用程式圖示"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"說明訊息區域"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"正在尋找你的臉孔…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"臉孔圖示"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"相容性縮放按鈕。"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"將較小螢幕的畫面放大在較大螢幕上顯示。"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"藍牙連線已建立。"</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"儲存空間"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"提示"</string>
     <string name="instant_apps" msgid="6647570248119804907">"免安裝應用程式"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"免安裝應用程式不必安裝就能使用。"</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"正在執行「<xliff:g id="APP">%1$s</xliff:g>」"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"已開啟免安裝應用程式。"</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"已開啟免安裝應用程式。輕觸即可瞭解詳情。"</string>
     <string name="app_info" msgid="6856026610594615344">"應用程式資訊"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"前往瀏覽器"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"前往網頁版"</string>
     <string name="mobile_data" msgid="7094582042819250762">"行動數據"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> - <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi 已關閉"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 0e4729b..085c3b3 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -103,10 +103,12 @@
     <string name="camera_label" msgid="7261107956054836961">"vula ikhamera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Khetha isakhiwo somsebenzi omusha"</string>
     <string name="cancel" msgid="6442560571259935130">"Khansela"</string>
+    <string name="accessibility_biometric_dialog_help_area" msgid="8953787076940186847">"Indawo yosizo lomlayezo"</string>
+    <string name="biometric_dialog_confirm" msgid="6468457350041712674">"Qinisekisa"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Thinta inzwa yesigxivizo somunwe"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Isithonjana sezigxivizo zeminwe"</string>
-    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Isithonjana sohlelo lokusebenza"</string>
-    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Indawo yosizo lomlayezo"</string>
+    <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Kufunwa wena…"</string>
+    <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Isithonjana sobuso"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Inkinobho evumelekile yokusondeza"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Sondeza kancane esikrinini esikhudlwana"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth ixhunyiwe"</string>
@@ -823,9 +825,11 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Isitoreji"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Ukubonisa"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Izinhlelo zokusebenza ezisheshayo"</string>
-    <string name="instant_apps_message" msgid="8116608994995104836">"Izinhlelo zokusebenza ezisheshayo azidingi ukufakwa."</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> esebenzayo"</string>
+    <string name="instant_apps_message" msgid="1183313016396018086">"Uhlelo lokusebenza luvulwe ngaphndle kokufakwa."</string>
+    <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Uhlelo lokusebenza luvulwe ngaphandle kokufakwa. Thepha ukuze ufunde kabanzi."</string>
     <string name="app_info" msgid="6856026610594615344">"Ulwazi lohlelo lokusebenza"</string>
-    <string name="go_to_web" msgid="2650669128861626071">"Iya kusiphequluli"</string>
+    <string name="go_to_web" msgid="1106022723459948514">"Iya kuwebhu"</string>
     <string name="mobile_data" msgid="7094582042819250762">"Idatha yeselula"</string>
     <string name="mobile_data_text_format" msgid="3526214522670876454">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"I-Wi-Fi ivaliwe"</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 4920fb2..d1320a3 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -160,13 +160,13 @@
     <color name="smart_reply_button_background">#ffffffff</color>
     <color name="smart_reply_button_stroke">#ffdadce0</color>
 
-    <!-- Fingerprint dialog colors -->
-    <color name="fingerprint_dialog_bg_color">#ffffffff</color> <!-- 100% white -->
-    <color name="fingerprint_dialog_text_dark_color">#dd000000</color> <!-- 87% black -->
-    <color name="fingerprint_dialog_text_light_color">#89000000</color> <!-- 54% black -->
-    <color name="fingerprint_dialog_dim_color">#80000000</color> <!-- 50% black -->
-    <color name="fingerprint_dialog_error_color">#fff44336</color> <!-- red -->
-    <color name="fingerprint_dialog_fingerprint_color">#ff008577</color> <!-- teal -->
+    <!-- Biometric dialog colors -->
+    <color name="biometric_dialog_bg_color">#ffffffff</color> <!-- 100% white -->
+    <color name="biometric_dialog_text_dark_color">#dd000000</color> <!-- 87% black -->
+    <color name="biometric_dialog_text_light_color">#89000000</color> <!-- 54% black -->
+    <color name="biometric_dialog_dim_color">#80000000</color> <!-- 50% black -->
+    <color name="biometric_dialog_error_color">#fff44336</color> <!-- red -->
+    <color name="biometric_dialog_biometric_color">#ff008577</color> <!-- teal -->
 
     <!-- Logout button -->
     <color name="logout_button_bg_color">#ccffffff</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 11bd392..2fbf42f 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -107,7 +107,7 @@
     <integer name="quick_settings_num_columns">3</integer>
 
     <!-- The number of rows in the QuickSettings -->
-    <integer name="quick_settings_num_rows">1</integer>
+    <integer name="quick_settings_max_rows">3</integer>
 
     <!-- The number of columns that the top level tiles span in the QuickSettings -->
     <integer name="quick_settings_user_time_settings_tile_span">1</integer>
@@ -146,19 +146,29 @@
     <!-- Should "LTE"/"4G" be shown instead of "LTE+"/"4G+" when on NETWORK_TYPE_LTE_CA? -->
     <bool name="config_hideLtePlus">false</bool>
 
-    <!-- milliseconds before the heads up notification auto-dismisses. -->
+    <!-- The number of milliseconds before the heads up notification auto-dismisses. -->
     <integer name="heads_up_notification_decay">5000</integer>
 
-    <!-- milliseconds after a heads up notification is pushed back
+    <!-- The number of milliseconds after a heads up notification is pushed back
      before the app can interrupt again. -->
     <integer name="heads_up_default_snooze_length_ms">60000</integer>
 
     <!-- Minimum display time for a heads up notification, in milliseconds. -->
     <integer name="heads_up_notification_minimum_time">2000</integer>
 
-    <!-- milliseconds before the heads up notification accepts touches. -->
+    <!-- The number of milliseconds before the heads up notification accepts touches. -->
     <integer name="touch_acceptance_delay">700</integer>
 
+    <!-- The number of milliseconds before the ambient notification auto-dismisses. This will
+         override the default pulse length. -->
+    <integer name="ambient_notification_decay">6000</integer>
+
+    <!-- Minimum display time for a heads up notification, in milliseconds. -->
+    <integer name="ambient_notification_minimum_time">2000</integer>
+
+    <!-- The number of milliseconds to extend ambient pulse by when prompted (e.g. on touch) -->
+    <integer name="ambient_notification_extension_time">6000</integer>
+
     <!-- The duration in seconds to wait before the dismiss buttons are shown. -->
     <integer name="recents_task_bar_dismiss_delay_seconds">1000</integer>
 
@@ -498,4 +508,7 @@
 
     <!-- Allow dragging the PIP to a location to close it -->
     <bool name="config_pipEnableDismissDragToEdge">true</bool>
+
+    <!-- SystemUI Plugins that can be loaded on user builds. -->
+    <string-array name="config_pluginWhitelist" translatable="false" />
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 26eadb5..7c355c9 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -650,7 +650,6 @@
     <dimen name="keyguard_affordance_icon_width">24dp</dimen>
 
     <dimen name="keyguard_indication_margin_bottom">65dp</dimen>
-    <dimen name="keyguard_indication_margin_bottom_ambient">16dp</dimen>
 
     <!-- The text size for battery level -->
     <dimen name="battery_level_text_size">12sp</dimen>
@@ -939,9 +938,8 @@
          burn-in on AOD. -->
     <dimen name="burn_in_prevention_offset_y">50dp</dimen>
 
-    <!-- The maximum offset in either direction that the charging indication moves vertically
-         to prevent burn-in on AOD. -->
-    <dimen name="charging_indication_burn_in_prevention_offset_y">5dp</dimen>
+    <!-- The maximum offset in either direction that icons move to prevent burn-in on AOD. -->
+    <dimen name="default_burn_in_prevention_offset">5dp</dimen>
 
     <dimen name="corner_size">8dp</dimen>
     <dimen name="top_padding">0dp</dimen>
@@ -955,7 +953,7 @@
     <dimen name="nav_content_padding">0dp</dimen>
     <dimen name="nav_quick_scrub_track_edge_padding">24dp</dimen>
     <dimen name="nav_quick_scrub_track_thickness">10dp</dimen>
-    <dimen name="nav_home_back_gesture_drag_limit">60dp</dimen>
+    <dimen name="nav_home_back_gesture_drag_limit">40dp</dimen>
 
     <!-- Navigation bar shadow params. -->
     <dimen name="nav_key_button_shadow_offset_x">0dp</dimen>
@@ -982,10 +980,10 @@
          the regular notification, when we have remote input history texts present. -->
     <dimen name="remote_input_history_extra_height">60dp</dimen>
 
-    <!-- Fingerprint Dialog values -->
-    <dimen name="fingerprint_dialog_fp_icon_size">64dp</dimen>
-    <dimen name="fingerprint_dialog_animation_translation_offset">350dp</dimen>
-    <dimen name="fingerprint_dialog_corner_size">4dp</dimen>
+    <!-- Biometric Dialog values -->
+    <dimen name="biometric_dialog_biometric_icon_size">64dp</dimen>
+    <dimen name="biometric_dialog_corner_size">4dp</dimen>
+    <dimen name="biometric_dialog_animation_translation_offset">350dp</dimen>
 
     <!-- Wireless Charging Animation values -->
     <dimen name="wireless_charging_dots_radius_start">0dp</dimen>
diff --git a/packages/SystemUI/res/values/integers.xml b/packages/SystemUI/res/values/integers.xml
index 87c4bbb..fd7a105 100644
--- a/packages/SystemUI/res/values/integers.xml
+++ b/packages/SystemUI/res/values/integers.xml
@@ -15,7 +15,7 @@
   ~ limitations under the License
   -->
 <resources>
-    <integer name="fingerprint_dialog_text_gravity">8388611</integer> <!-- gravity start -->
+    <integer name="biometric_dialog_text_gravity">8388611</integer> <!-- gravity start -->
 
     <!-- Action footer width used for layout_width to indicate WRAP_CONTENT (along with a weight of
          0) as we can allow the carrier text to stretch as far as needed in the QS footer. -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 36f97cd..2b51aaa 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -257,14 +257,20 @@
     <!-- Button name for "Cancel". [CHAR LIMIT=NONE] -->
     <string name="cancel">Cancel</string>
 
+    <!-- Content description for the error/help message are when the system-provided fingerprint dialog is showing, for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_biometric_dialog_help_area">Help message area</string>
+    <!-- Message shown when a biometric is authenticated, asking the user to confirm authentication [CHAR LIMIT=30] -->
+    <string name="biometric_dialog_confirm">Confirm</string>
+
     <!-- Message shown when the system-provided fingerprint dialog is shown, asking for authentication -->
     <string name="fingerprint_dialog_touch_sensor">Touch the fingerprint sensor</string>
     <!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_fingerprint_dialog_fingerprint_icon">Fingerprint icon</string>
-    <!-- Content description of the application icon when the system-provided fingerprint dialog is showing, for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_fingerprint_dialog_app_icon">Application icon</string>
-    <!-- Content description for the error/help message are when the system-provided fingerprint dialog is showing, for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_fingerprint_dialog_help_area">Help message area</string>
+
+    <!-- Message shown when the system-provided face dialog is shown, asking for authentication [CHAR LIMIT=30] -->
+    <string name="face_dialog_looking_for_face">Looking for you\u2026</string>
+    <!-- Content description of the face icon when the system-provided face dialog is showing, for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_face_dialog_face_icon">Face icon</string>
 
     <!-- Content description of the compatibility zoom button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_compatibility_zoom_button">Compatibility zoom button.</string>
@@ -2132,14 +2138,23 @@
     <!-- App label of the instant apps notification [CHAR LIMIT=60] -->
     <string name="instant_apps">Instant Apps</string>
 
-    <!-- Message of the instant apps notification indicating they don't need install [CHAR LIMIT=NONE] -->
-    <string name="instant_apps_message">Instant apps don\'t require installation.</string>
+    <!-- Title of notification indicating that an instant app is running. [CHAR LIMIT=60] -->
+    <string name="instant_apps_title"><xliff:g id="app" example="Gmail">%1$s</xliff:g> running</string>
+
+    <!-- Message of the instant apps notification indicating they don't need install. [CHAR LIMIT=NONE] -->
+    <string name="instant_apps_message">App opened without being installed.</string>
+
+    <!-- Message of the instant apps notification indicating they don't need install, plus a link to more information. [CHAR LIMIT=NONE] -->
+    <string name="instant_apps_message_with_help">App opened without being installed. Tap to learn more.</string>
+
+    <!-- URL of the webpage that explains instant apps. -->
+    <string name="instant_apps_help_url" translatable="false"></string>
 
     <!-- Action label for launching app info on the specified app [CHAR LIMIT=20] -->
     <string name="app_info">App info</string>
 
     <!-- Action label for switching to a browser for an instant app [CHAR LIMIT=20] -->
-    <string name="go_to_web">Go to browser</string>
+    <string name="go_to_web">Go to web</string>
 
     <!-- Quick settings tile for toggling mobile data [CHAR LIMIT=20] -->
     <string name="mobile_data">Mobile data</string>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/RecentsTransition.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/RecentsTransition.java
index ab89043..e253360 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/RecentsTransition.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/RecentsTransition.java
@@ -21,13 +21,11 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.GraphicBuffer;
+import android.graphics.Picture;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IRemoteCallback;
 import android.os.RemoteException;
-import android.view.DisplayListCanvas;
-import android.view.RenderNode;
-import android.view.ThreadedRenderer;
 import android.view.View;
 
 import java.util.function.Consumer;
@@ -108,12 +106,10 @@
      *         null if we were unable to allocate a hardware bitmap.
      */
     public static Bitmap createHardwareBitmap(int width, int height, Consumer<Canvas> consumer) {
-        RenderNode node = RenderNode.create("RecentsTransition", null);
-        node.setLeftTopRightBottom(0, 0, width, height);
-        node.setClipToBounds(false);
-        DisplayListCanvas c = node.start(width, height);
-        consumer.accept(c);
-        node.end(c);
-        return ThreadedRenderer.createHardwareBitmap(node, width, height);
+        final Picture picture = new Picture();
+        final Canvas canvas = picture.beginRecording(width, height);
+        consumer.accept(canvas);
+        picture.endRecording();
+        return Bitmap.createBitmap(picture);
     }
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index b04d047..c7910f9 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -342,6 +342,20 @@
     }
 
     /**
+     * Moves an already resumed task to the side of the screen to initiate split screen.
+     */
+    public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode,
+            Rect initialBounds) {
+        try {
+            return ActivityTaskManager.getService().setTaskWindowingModeSplitScreenPrimary(taskId,
+                    createMode, true /* onTop */, false /* animate */, initialBounds,
+                    true /* showRecents */);
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    /**
      * Registers a task stack listener with the system.
      * This should be called on the main thread.
      */
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
index d83b36d..3191d14 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
@@ -151,6 +151,25 @@
         }
     }
 
+    public void setPipVisibility(final boolean visible) {
+        try {
+            WindowManagerGlobal.getWindowManagerService().setPipVisibility(visible);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Unable to reach window manager", e);
+        }
+    }
+
+    /**
+     * @return whether there is a soft nav bar.
+     */
+    public boolean hasSoftNavigationBar() {
+        try {
+            return WindowManagerGlobal.getWindowManagerService().hasNavigationBar();
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
     /**
      * @return The side of the screen where navigation bar is positioned.
      * @see #NAV_BAR_POS_RIGHT
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index 5ffdc7b..2daa33b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -377,6 +377,7 @@
 
     @Override
     public void onResume(int reason) {
+        displayDefaultSecurityMessage();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index b159b39..b8df3c06 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -342,12 +342,11 @@
                 case SimPuk:
                     // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
                     SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
-                    if (securityMode != SecurityMode.None
-                            || !mLockPatternUtils.isLockScreenDisabled(
+                    if (securityMode == SecurityMode.None || mLockPatternUtils.isLockScreenDisabled(
                             KeyguardUpdateMonitor.getCurrentUser())) {
-                        showSecurityScreen(securityMode);
-                    } else {
                         finish = true;
+                    } else {
+                        showSecurityScreen(securityMode);
                     }
                     break;
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index ff6a1c9..f1b53fe 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -39,9 +39,9 @@
 import android.app.UserSwitchObserver;
 import android.app.admin.DevicePolicyManager;
 import android.app.trust.TrustManager;
-import android.hardware.biometrics.BiometricSourceType;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -49,11 +49,13 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.database.ContentObserver;
+import android.hardware.biometrics.BiometricSourceType;
 import android.hardware.face.FaceManager;
 import android.hardware.fingerprint.FingerprintManager;
 import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
 import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
 import android.media.AudioManager;
+import android.net.Uri;
 import android.os.BatteryManager;
 import android.os.CancellationSignal;
 import android.os.Handler;
@@ -75,7 +77,6 @@
 import android.telephony.TelephonyManager;
 import android.util.Log;
 import android.util.SparseBooleanArray;
-import android.util.SparseIntArray;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.IccCardConstants;
@@ -85,9 +86,8 @@
 import com.android.internal.util.Preconditions;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.settingslib.WirelessUtils;
-import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
-
+import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.google.android.collect.Lists;
 
 import java.io.FileDescriptor;
@@ -250,6 +250,51 @@
     private static final int HW_UNAVAILABLE_TIMEOUT = 3000; // ms
     private static final int HW_UNAVAILABLE_RETRY_MAX = 3;
 
+    private class SettingObserver extends ContentObserver {
+        private final Uri FACE_UNLOCK_KEYGUARD_ENABLED =
+                Settings.Secure.getUriFor(Settings.Secure.FACE_UNLOCK_KEYGUARD_ENABLED);
+
+        private final ContentResolver mContentResolver;
+
+        /**
+         * Creates a content observer.
+         *
+         * @param handler The handler to run {@link #onChange} on, or null if none.
+         */
+        public SettingObserver(Handler handler) {
+            super(handler);
+            mContentResolver = mContext.getContentResolver();
+            updateContentObserver();
+        }
+
+        public void updateContentObserver() {
+            mContentResolver.unregisterContentObserver(this);
+            mContentResolver.registerContentObserver(FACE_UNLOCK_KEYGUARD_ENABLED,
+                    false /* notifyForDescendents */,
+                    this,
+                    UserHandle.USER_CURRENT);
+
+            // Update the value immediately
+            onChange(true /* selfChange */, FACE_UNLOCK_KEYGUARD_ENABLED);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            if (FACE_UNLOCK_KEYGUARD_ENABLED.equals(uri)) {
+                    mFaceSettingEnabledForUser =
+                            Settings.Secure.getIntForUser(
+                                    mContentResolver,
+                                    Settings.Secure.FACE_UNLOCK_KEYGUARD_ENABLED,
+                                    1 /* default */,
+                                    UserHandle.USER_CURRENT) != 0;
+                    updateBiometricListeningState();
+            }
+        }
+    }
+
+    private final SettingObserver mSettingObserver;
+    private boolean mFaceSettingEnabledForUser;
+
     private final Handler mHandler = new Handler(Looper.getMainLooper()) {
         @Override
         public void handleMessage(Message msg) {
@@ -1389,6 +1434,7 @@
         mSubscriptionManager = SubscriptionManager.from(context);
         mDeviceProvisioned = isDeviceProvisionedInSettingsDb();
         mStrongAuthTracker = new StrongAuthTracker(context);
+        mSettingObserver = new SettingObserver(mHandler);
 
         // Since device can't be un-provisioned, we only need to register a content observer
         // to update mDeviceProvisioned when we are...
@@ -1549,7 +1595,7 @@
                 (mBouncer && !mKeyguardGoingAway) || mGoingToSleep ||
                 shouldListenForFaceAssistant() || (mKeyguardOccluded && mIsDreaming))
                 && !mSwitchingUser && !isFaceDisabled(getCurrentUser())
-                && !mKeyguardGoingAway;
+                && !mKeyguardGoingAway && mFaceSettingEnabledForUser;
     }
 
 
@@ -1719,6 +1765,7 @@
      * Handle {@link #MSG_USER_SWITCH_COMPLETE}
      */
     private void handleUserSwitchComplete(int userId) {
+        mSettingObserver.updateContentObserver();
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -2170,8 +2217,8 @@
         }
     }
 
-    private final SysUiTaskStackChangeListener
-            mTaskStackListener = new SysUiTaskStackChangeListener() {
+    private final TaskStackChangeListener
+            mTaskStackListener = new TaskStackChangeListener() {
         @Override
         public void onTaskStackChangedBackground() {
             try {
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 77f4bf5..408e599 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -256,12 +256,6 @@
                 Log.d(TAG, "onSurfaceRedrawNeeded");
             }
             super.onSurfaceRedrawNeeded(holder);
-            // At the end of this method we should have drawn into the surface.
-            // This means that the bitmap should be loaded synchronously if
-            // it was already unloaded.
-            if (mBackground == null) {
-                updateBitmap(mWallpaperManager.getBitmap(true /* hardware */));
-            }
             mSurfaceRedrawNeeded = true;
             drawFrame();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index bd2b7a5..1af2156 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -16,6 +16,11 @@
 
 package com.android.systemui;
 
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_SWIPE_UP;
+import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
+import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType;
+
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -33,11 +38,7 @@
 import android.provider.Settings;
 import android.util.Log;
 import android.view.MotionEvent;
-
 import com.android.systemui.OverviewProxyService.OverviewProxyListener;
-import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent;
-import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.shared.recents.ISystemUiProxy;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -46,17 +47,11 @@
 import com.android.systemui.statusbar.policy.CallbackController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
-
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
 
-import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
-import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_SWIPE_UP;
-import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
-import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType;
-
 /**
  * Class to send information from overview to launcher with a binder.
  */
@@ -133,7 +128,10 @@
             }
             long token = Binder.clearCallingIdentity();
             try {
-                EventBus.getDefault().post(new DockedFirstAnimationFrameEvent());
+                Divider divider = SysUiServiceProvider.getComponent(mContext, Divider.class);
+                if (divider != null) {
+                    divider.onDockedFirstAnimationFrame();
+                }
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -314,8 +312,7 @@
                 getDefaultInteractionFlags());
 
         // Listen for the package update changes.
-        if (SystemServicesProxy.getInstance(context)
-                .isSystemUser(mDeviceProvisionedController.getCurrentUser())) {
+        if (mDeviceProvisionedController.getCurrentUser() == UserHandle.USER_SYSTEM) {
             updateEnabledState();
             mDeviceProvisionedController.addCallback(mDeviceProvisionedCallback);
             IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
diff --git a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
index f9dbf4a..fb343f9 100644
--- a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
@@ -22,27 +22,10 @@
 
 public interface RecentsComponent {
     void showRecentApps(boolean triggeredFromAltTab);
-    void showNextAffiliatedTask();
-    void showPrevAffiliatedTask();
 
     /**
      * Docks the top-most task and opens recents.
      */
-    boolean splitPrimaryTask(int dragMode, int stackCreateMode, Rect initialBounds,
+    boolean splitPrimaryTask(int stackCreateMode, Rect initialBounds,
             int metricsDockAction);
-
-    /**
-     * Called during a drag-from-navbar-in gesture.
-     *
-     * @param distanceFromTop the distance of the current drag in gesture from the top of the
-     *                        screen
-     */
-    void onDraggingInRecents(float distanceFromTop);
-
-    /**
-     * Called when the gesture to drag in recents ended.
-     *
-     * @param velocity the velocity of the finger when releasing it in pixels per second
-     */
-    void onDraggingInRecentsEnded(float velocity);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 044cc5c..48181bc 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -187,9 +187,11 @@
 
         mOverlay.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
         mOverlay.setAlpha(0);
+        mOverlay.setAllowForceDark(false);
 
         mBottomOverlay.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
         mBottomOverlay.setAlpha(0);
+        mBottomOverlay.setAllowForceDark(false);
 
         updateViews();
 
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index a3b5395..0215fda 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -61,13 +61,14 @@
     public static final float SWIPED_FAR_ENOUGH_SIZE_FRACTION = 0.6f;
     static final float MAX_SCROLL_SIZE_FRACTION = 0.3f;
 
+    protected final Handler mHandler;
+
     private float mMinSwipeProgress = 0f;
     private float mMaxSwipeProgress = 1f;
 
     private final FlingAnimationUtils mFlingAnimationUtils;
     private float mPagingTouchSlop;
     private final Callback mCallback;
-    private final Handler mHandler;
     private final int mSwipeDirection;
     private final VelocityTracker mVelocityTracker;
     private final FalsingManager mFalsingManager;
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 04d72ce..258b6f6 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -30,6 +30,7 @@
 import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.keyguard.DismissCallbackRegistry;
 import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.statusbar.AmbientPulseManager;
 import com.android.systemui.statusbar.KeyguardIndicationController;
 import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
@@ -137,6 +138,7 @@
         providers.put(NotificationGroupManager.class, NotificationGroupManager::new);
         providers.put(NotificationMediaManager.class, () -> new NotificationMediaManager(context));
         providers.put(NotificationGutsManager.class, () -> new NotificationGutsManager(context));
+        providers.put(AmbientPulseManager.class, () -> new AmbientPulseManager(context));
         providers.put(NotificationBlockingHelperManager.class,
                 () -> new NotificationBlockingHelperManager(context));
         providers.put(NotificationRemoteInputManager.class,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
index 8fe577a..8fc4689 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.BiometricPrompt;
 import android.hardware.biometrics.IBiometricPromptReceiver;
 import android.os.Bundle;
@@ -31,9 +32,12 @@
 import com.android.systemui.SystemUI;
 import com.android.systemui.statusbar.CommandQueue;
 
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * Receives messages sent from AuthenticationClient and shows the appropriate biometric UI (e.g.
- * FingerprintDialogView).
+ * BiometricDialogView).
  */
 public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callbacks {
     private static final String TAG = "BiometricDialogImpl";
@@ -48,7 +52,8 @@
     private static final int MSG_USER_CANCELED = 7;
     private static final int MSG_BUTTON_POSITIVE = 8;
 
-    private FingerprintDialogView mDialogView;
+    private Map<Integer, BiometricDialogView> mDialogs; // BiometricAuthenticator type, view
+    private BiometricDialogView mCurrentDialog;
     private WindowManager mWindowManager;
     private IBiometricPromptReceiver mReceiver;
     private boolean mDialogShowing;
@@ -111,16 +116,25 @@
 
     @Override
     public void start() {
-        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
-            return;
+        final PackageManager pm = mContext.getPackageManager();
+        mDialogs = new HashMap<>();
+        if (pm.hasSystemFeature(PackageManager.FEATURE_FACE)) {
+            mDialogs.put(BiometricAuthenticator.TYPE_FACE, new FaceDialogView(mContext, mCallback));
         }
-        getComponent(CommandQueue.class).addCallbacks(this);
-        mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
-        mDialogView = new FingerprintDialogView(mContext, mCallback);
+        if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
+            mDialogs.put(BiometricAuthenticator.TYPE_FINGERPRINT,
+                    new FingerprintDialogView(mContext, mCallback));
+        }
+
+        if (!mDialogs.isEmpty()) {
+            getComponent(CommandQueue.class).addCallbacks(this);
+            mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+        }
     }
 
     @Override
-    public void showBiometricDialog(Bundle bundle, IBiometricPromptReceiver receiver, int type) {
+    public void showBiometricDialog(Bundle bundle, IBiometricPromptReceiver receiver, int type,
+            boolean requireConfirmation) {
         if (DEBUG) Log.d(TAG, "showBiometricDialog, type: " + type);
         // Remove these messages as they are part of the previous client
         mHandler.removeMessages(MSG_BIOMETRIC_ERROR);
@@ -129,6 +143,8 @@
         SomeArgs args = SomeArgs.obtain();
         args.arg1 = bundle;
         args.arg2 = receiver;
+        args.argi1 = type;
+        args.arg3 = requireConfirmation;
         mHandler.obtainMessage(MSG_SHOW_DIALOG, args).sendToTarget();
     }
 
@@ -157,33 +173,41 @@
     }
 
     private void handleShowDialog(SomeArgs args) {
+        final int type = args.argi1;
+        mCurrentDialog = mDialogs.get(type);
+
         if (DEBUG) Log.d(TAG, "handleShowDialog, isAnimatingAway: "
-                + mDialogView.isAnimatingAway());
-        if (mDialogView.isAnimatingAway()) {
-            mDialogView.forceRemove();
+                + mCurrentDialog.isAnimatingAway() + " type: " + type);
+
+        if (mCurrentDialog.isAnimatingAway()) {
+            mCurrentDialog.forceRemove();
         } else if (mDialogShowing) {
             Log.w(TAG, "Dialog already showing");
             return;
         }
         mReceiver = (IBiometricPromptReceiver) args.arg2;
-        mDialogView.setBundle((Bundle)args.arg1);
-        mWindowManager.addView(mDialogView, mDialogView.getLayoutParams());
+        mCurrentDialog.setBundle((Bundle)args.arg1);
+        mCurrentDialog.setRequireConfirmation((boolean)args.arg3);
+        mWindowManager.addView(mCurrentDialog, mCurrentDialog.getLayoutParams());
         mDialogShowing = true;
     }
 
     private void handleBiometricAuthenticated() {
         if (DEBUG) Log.d(TAG, "handleBiometricAuthenticated");
 
-        // TODO: announce correct string depending on modality
-        mDialogView.announceForAccessibility(
-                mContext.getResources().getText(
-                        com.android.internal.R.string.fingerprint_authenticated));
-        handleHideDialog(false /* userCanceled */);
+        mCurrentDialog.announceForAccessibility(
+                mContext.getResources()
+                        .getText(mCurrentDialog.getAuthenticatedAccessibilityResourceId()));
+        if (mCurrentDialog.requiresConfirmation()) {
+            mCurrentDialog.showConfirmationButton();
+        } else {
+            handleHideDialog(false /* userCanceled */);
+        }
     }
 
     private void handleBiometricHelp(String message) {
         if (DEBUG) Log.d(TAG, "handleBiometricHelp: " + message);
-        mDialogView.showHelpMessage(message);
+        mCurrentDialog.showHelpMessage(message);
     }
 
     private void handleBiometricError(String error) {
@@ -192,7 +216,7 @@
             if (DEBUG) Log.d(TAG, "Dialog already dismissed");
             return;
         }
-        mDialogView.showErrorMessage(error);
+        mCurrentDialog.showErrorMessage(error);
     }
 
     private void handleHideDialog(boolean userCanceled) {
@@ -212,7 +236,7 @@
         }
         mReceiver = null;
         mDialogShowing = false;
-        mDialogView.startDismiss();
+        mCurrentDialog.startDismiss();
     }
 
     private void handleButtonNegative() {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
new file mode 100644
index 0000000..c90861e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
@@ -0,0 +1,363 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.biometrics;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.hardware.biometrics.BiometricPrompt;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.text.TextUtils;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.animation.Interpolator;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+
+/**
+ * Abstract base class. Shows a dialog for BiometricPrompt.
+ */
+public abstract class BiometricDialogView extends LinearLayout {
+
+    private static final String TAG = "BiometricDialogView";
+
+    private static final int ANIMATION_DURATION_SHOW = 250; // ms
+    private static final int ANIMATION_DURATION_AWAY = 350; // ms
+
+    private static final int MSG_CLEAR_MESSAGE = 1;
+
+    protected static final int STATE_NONE = 0;
+    protected static final int STATE_AUTHENTICATING = 1;
+    protected static final int STATE_ERROR = 2;
+    protected static final int STATE_AUTHENTICATED = 3;
+
+    private final IBinder mWindowToken = new Binder();
+    private final Interpolator mLinearOutSlowIn;
+    private final WindowManager mWindowManager;
+    private final float mAnimationTranslationOffset;
+    private final int mErrorColor;
+    private final int mTextColor;
+    private final float mDisplayWidth;
+    private final DialogViewCallback mCallback;
+
+    private ViewGroup mLayout;
+    private final TextView mErrorText;
+    private Bundle mBundle;
+    private final LinearLayout mDialog;
+    private int mLastState;
+    private boolean mAnimatingAway;
+    private boolean mWasForceRemoved;
+    protected boolean mRequireConfirmation;
+
+    protected abstract void updateIcon(int lastState, int newState);
+    protected abstract int getHintStringResourceId();
+    protected abstract int getAuthenticatedAccessibilityResourceId();
+    protected abstract int getIconDescriptionResourceId();
+
+    private final Runnable mShowAnimationRunnable = new Runnable() {
+        @Override
+        public void run() {
+            mLayout.animate()
+                    .alpha(1f)
+                    .setDuration(ANIMATION_DURATION_SHOW)
+                    .setInterpolator(mLinearOutSlowIn)
+                    .withLayer()
+                    .start();
+            mDialog.animate()
+                    .translationY(0)
+                    .setDuration(ANIMATION_DURATION_SHOW)
+                    .setInterpolator(mLinearOutSlowIn)
+                    .withLayer()
+                    .start();
+        }
+    };
+
+    private Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch(msg.what) {
+                case MSG_CLEAR_MESSAGE:
+                    handleClearMessage();
+                    break;
+                default:
+                    Log.e(TAG, "Unhandled message: " + msg.what);
+                    break;
+            }
+        }
+    };
+
+    public BiometricDialogView(Context context, DialogViewCallback callback) {
+        super(context);
+        mCallback = callback;
+        mLinearOutSlowIn = Interpolators.LINEAR_OUT_SLOW_IN;
+        mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+        mAnimationTranslationOffset = getResources()
+                .getDimension(R.dimen.biometric_dialog_animation_translation_offset);
+        mErrorColor = Color.parseColor(
+                getResources().getString(R.color.biometric_dialog_error_color));
+        mTextColor = Color.parseColor(
+                getResources().getString(R.color.biometric_dialog_text_light_color));
+
+        DisplayMetrics metrics = new DisplayMetrics();
+        mWindowManager.getDefaultDisplay().getMetrics(metrics);
+        mDisplayWidth = metrics.widthPixels;
+
+        // Create the dialog
+        LayoutInflater factory = LayoutInflater.from(getContext());
+        mLayout = (ViewGroup) factory.inflate(R.layout.biometric_dialog, this, false);
+        addView(mLayout);
+
+        mDialog = mLayout.findViewById(R.id.dialog);
+
+        mErrorText = mLayout.findViewById(R.id.error);
+
+        mLayout.setOnKeyListener(new View.OnKeyListener() {
+            boolean downPressed = false;
+            @Override
+            public boolean onKey(View v, int keyCode, KeyEvent event) {
+                if (keyCode != KeyEvent.KEYCODE_BACK) {
+                    return false;
+                }
+                if (event.getAction() == KeyEvent.ACTION_DOWN && downPressed == false) {
+                    downPressed = true;
+                } else if (event.getAction() == KeyEvent.ACTION_DOWN) {
+                    downPressed = false;
+                } else if (event.getAction() == KeyEvent.ACTION_UP && downPressed == true) {
+                    downPressed = false;
+                    mCallback.onUserCanceled();
+                }
+                return true;
+            }
+        });
+
+        final View space = mLayout.findViewById(R.id.space);
+        final View leftSpace = mLayout.findViewById(R.id.left_space);
+        final View rightSpace = mLayout.findViewById(R.id.right_space);
+        final Button negative = mLayout.findViewById(R.id.button2);
+        final Button positive = mLayout.findViewById(R.id.button1);
+        final ImageView icon = mLayout.findViewById(R.id.biometric_icon);
+
+        icon.setContentDescription(getResources().getString(getIconDescriptionResourceId()));
+        mErrorText.setText(getResources().getString(getHintStringResourceId()));
+
+        setDismissesDialog(space);
+        setDismissesDialog(leftSpace);
+        setDismissesDialog(rightSpace);
+
+        negative.setOnClickListener((View v) -> {
+            mCallback.onNegativePressed();
+        });
+
+        positive.setOnClickListener((View v) -> {
+            mCallback.onPositivePressed();
+        });
+
+        mLayout.setFocusableInTouchMode(true);
+        mLayout.requestFocus();
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        final TextView title = mLayout.findViewById(R.id.title);
+        final TextView subtitle = mLayout.findViewById(R.id.subtitle);
+        final TextView description = mLayout.findViewById(R.id.description);
+        final Button negative = mLayout.findViewById(R.id.button2);
+        final Button positive = mLayout.findViewById(R.id.button1);
+
+        mDialog.getLayoutParams().width = (int) mDisplayWidth;
+
+        mLastState = STATE_NONE;
+        updateState(STATE_AUTHENTICATING);
+
+        title.setText(mBundle.getCharSequence(BiometricPrompt.KEY_TITLE));
+        title.setSelected(true);
+
+        positive.setVisibility(View.INVISIBLE);
+
+        final CharSequence subtitleText = mBundle.getCharSequence(BiometricPrompt.KEY_SUBTITLE);
+        if (TextUtils.isEmpty(subtitleText)) {
+            subtitle.setVisibility(View.GONE);
+        } else {
+            subtitle.setVisibility(View.VISIBLE);
+            subtitle.setText(subtitleText);
+        }
+
+        final CharSequence descriptionText = mBundle.getCharSequence(BiometricPrompt.KEY_DESCRIPTION);
+        if (TextUtils.isEmpty(descriptionText)) {
+            description.setVisibility(View.GONE);
+        } else {
+            description.setVisibility(View.VISIBLE);
+            description.setText(descriptionText);
+        }
+
+        negative.setText(mBundle.getCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT));
+
+        if (!mWasForceRemoved) {
+            // Dim the background and slide the dialog up
+            mDialog.setTranslationY(mAnimationTranslationOffset);
+            mLayout.setAlpha(0f);
+            postOnAnimation(mShowAnimationRunnable);
+        } else {
+            // Show the dialog immediately
+            mLayout.animate().cancel();
+            mDialog.animate().cancel();
+            mDialog.setAlpha(1.0f);
+            mDialog.setTranslationY(0);
+            mLayout.setAlpha(1.0f);
+        }
+        mWasForceRemoved = false;
+    }
+
+    private void setDismissesDialog(View v) {
+        v.setClickable(true);
+        v.setOnTouchListener((View view, MotionEvent event) -> {
+            mCallback.onUserCanceled();
+            return true;
+        });
+    }
+
+    public void startDismiss() {
+        mAnimatingAway = true;
+
+        final Runnable endActionRunnable = new Runnable() {
+            @Override
+            public void run() {
+                mWindowManager.removeView(BiometricDialogView.this);
+                mAnimatingAway = false;
+            }
+        };
+
+        postOnAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mLayout.animate()
+                        .alpha(0f)
+                        .setDuration(ANIMATION_DURATION_AWAY)
+                        .setInterpolator(mLinearOutSlowIn)
+                        .withLayer()
+                        .start();
+                mDialog.animate()
+                        .translationY(mAnimationTranslationOffset)
+                        .setDuration(ANIMATION_DURATION_AWAY)
+                        .setInterpolator(mLinearOutSlowIn)
+                        .withLayer()
+                        .withEndAction(endActionRunnable)
+                        .start();
+            }
+        });
+    }
+
+    /**
+     * Force remove the window, cancelling any animation that's happening. This should only be
+     * called if we want to quickly show the dialog again (e.g. on rotation). Calling this method
+     * will cause the dialog to show without an animation the next time it's attached.
+     */
+    public void forceRemove() {
+        mLayout.animate().cancel();
+        mDialog.animate().cancel();
+        mWindowManager.removeView(BiometricDialogView.this);
+        mAnimatingAway = false;
+        mWasForceRemoved = true;
+    }
+
+    public boolean isAnimatingAway() {
+        return mAnimatingAway;
+    }
+
+    public void setBundle(Bundle bundle) {
+        mBundle = bundle;
+    }
+
+    public void setRequireConfirmation(boolean requireConfirmation) {
+        mRequireConfirmation = requireConfirmation;
+    }
+
+    public boolean requiresConfirmation() {
+        return mRequireConfirmation;
+    }
+
+    public void showConfirmationButton() {
+        final Button positive = mLayout.findViewById(R.id.button1);
+        positive.setVisibility(View.VISIBLE);
+    }
+
+    public ViewGroup getLayout() {
+        return mLayout;
+    }
+
+    // Clears the temporary message and shows the help message.
+    private void handleClearMessage() {
+        updateState(STATE_AUTHENTICATING);
+        mErrorText.setText(getHintStringResourceId());
+        mErrorText.setTextColor(mTextColor);
+    }
+
+    // Shows an error/help message
+    private void showTemporaryMessage(String message) {
+        mHandler.removeMessages(MSG_CLEAR_MESSAGE);
+        updateState(STATE_ERROR);
+        mErrorText.setText(message);
+        mErrorText.setTextColor(mErrorColor);
+        mErrorText.setContentDescription(message);
+        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CLEAR_MESSAGE),
+                BiometricPrompt.HIDE_DIALOG_DELAY);
+    }
+
+    public void showHelpMessage(String message) {
+        showTemporaryMessage(message);
+    }
+
+    public void showErrorMessage(String error) {
+        showTemporaryMessage(error);
+        mCallback.onErrorShown();
+    }
+
+    private void updateState(int newState) {
+        updateIcon(mLastState, newState);
+        mLastState = newState;
+    }
+
+    public WindowManager.LayoutParams getLayoutParams() {
+        final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
+                WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
+                PixelFormat.TRANSLUCENT);
+        lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+        lp.setTitle("BiometricDialogView");
+        lp.token = mWindowToken;
+        return lp;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
new file mode 100644
index 0000000..feef3a6d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.biometrics;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.widget.ImageView;
+
+import com.android.systemui.R;
+
+/**
+ * This class loads the view for the system-provided dialog. The view consists of:
+ * Application Icon, Title, Subtitle, Description, Fingerprint Icon, Error/Help message area,
+ * and positive/negative buttons.
+ */
+public class FaceDialogView extends BiometricDialogView {
+    public FaceDialogView(Context context,
+            DialogViewCallback callback) {
+        super(context, callback);
+    }
+
+    @Override
+    protected int getHintStringResourceId() {
+        return R.string.face_dialog_looking_for_face;
+    }
+
+    @Override
+    protected int getAuthenticatedAccessibilityResourceId() {
+        if (mRequireConfirmation) {
+            return com.android.internal.R.string.face_authenticated_confirmation_required;
+        } else {
+            return com.android.internal.R.string.face_authenticated_no_confirmation_required;
+        }
+    }
+
+    @Override
+    protected int getIconDescriptionResourceId() {
+        return R.string.accessibility_face_dialog_face_icon;
+    }
+
+    @Override
+    protected void updateIcon(int lastState, int newState) {
+        Drawable icon = mContext.getDrawable(R.drawable.face_dialog_icon);
+
+        final ImageView faceIcon = getLayout().findViewById(R.id.biometric_icon);
+        faceIcon.setImageDrawable(icon);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java
index 68c2c42..38a69a9 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java
@@ -17,32 +17,11 @@
 package com.android.systemui.biometrics;
 
 import android.content.Context;
-import android.graphics.Color;
-import android.graphics.PixelFormat;
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable;
-import android.hardware.biometrics.BiometricPrompt;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.text.TextUtils;
-import android.util.DisplayMetrics;
 import android.util.Log;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.view.animation.Interpolator;
-import android.widget.Button;
 import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
 
-import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 
 /**
@@ -50,288 +29,27 @@
  * Application Icon, Title, Subtitle, Description, Fingerprint Icon, Error/Help message area,
  * and positive/negative buttons.
  */
-public class FingerprintDialogView extends LinearLayout {
-
+public class FingerprintDialogView extends BiometricDialogView {
     private static final String TAG = "FingerprintDialogView";
 
-    private static final int ANIMATION_DURATION_SHOW = 250; // ms
-    private static final int ANIMATION_DURATION_AWAY = 350; // ms
-
-    private static final int MSG_CLEAR_MESSAGE = 1;
-
-    private static final int STATE_NONE = 0;
-    private static final int STATE_FINGERPRINT = 1;
-    private static final int STATE_FINGERPRINT_ERROR = 2;
-    private static final int STATE_FINGERPRINT_AUTHENTICATED = 3;
-
-    private final IBinder mWindowToken = new Binder();
-    private final Interpolator mLinearOutSlowIn;
-    private final WindowManager mWindowManager;
-    private final float mAnimationTranslationOffset;
-    private final int mErrorColor;
-    private final int mTextColor;
-    private final int mFingerprintColor;
-    private final float mDisplayWidth;
-    private final DialogViewCallback mCallback;
-
-    private ViewGroup mLayout;
-    private final TextView mErrorText;
-    private Bundle mBundle;
-    private final LinearLayout mDialog;
-    private int mLastState;
-    private boolean mAnimatingAway;
-    private boolean mWasForceRemoved;
-
-    private final Runnable mShowAnimationRunnable = new Runnable() {
-        @Override
-        public void run() {
-            mLayout.animate()
-                    .alpha(1f)
-                    .setDuration(ANIMATION_DURATION_SHOW)
-                    .setInterpolator(mLinearOutSlowIn)
-                    .withLayer()
-                    .start();
-            mDialog.animate()
-                    .translationY(0)
-                    .setDuration(ANIMATION_DURATION_SHOW)
-                    .setInterpolator(mLinearOutSlowIn)
-                    .withLayer()
-                    .start();
-        }
-    };
-
-    private Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            switch(msg.what) {
-                case MSG_CLEAR_MESSAGE:
-                    handleClearMessage();
-                    break;
-                default:
-                    Log.e(TAG, "Unhandled message: " + msg.what);
-                    break;
-            }
-        }
-    };
-
-    public FingerprintDialogView(Context context, DialogViewCallback callback) {
-        super(context);
-        mCallback = callback;
-        mLinearOutSlowIn = Interpolators.LINEAR_OUT_SLOW_IN;
-        mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
-        mAnimationTranslationOffset = getResources()
-                .getDimension(R.dimen.fingerprint_dialog_animation_translation_offset);
-        mErrorColor = Color.parseColor(
-                getResources().getString(R.color.fingerprint_dialog_error_color));
-        mTextColor = Color.parseColor(
-                getResources().getString(R.color.fingerprint_dialog_text_light_color));
-        mFingerprintColor = Color.parseColor(
-                getResources().getString(R.color.fingerprint_dialog_fingerprint_color));
-
-        DisplayMetrics metrics = new DisplayMetrics();
-        mWindowManager.getDefaultDisplay().getMetrics(metrics);
-        mDisplayWidth = metrics.widthPixels;
-
-        // Create the dialog
-        LayoutInflater factory = LayoutInflater.from(getContext());
-        mLayout = (ViewGroup) factory.inflate(R.layout.fingerprint_dialog, this, false);
-        addView(mLayout);
-
-        mDialog = mLayout.findViewById(R.id.dialog);
-
-        mErrorText = mLayout.findViewById(R.id.error);
-
-        mLayout.setOnKeyListener(new View.OnKeyListener() {
-            boolean downPressed = false;
-            @Override
-            public boolean onKey(View v, int keyCode, KeyEvent event) {
-                if (keyCode != KeyEvent.KEYCODE_BACK) {
-                    return false;
-                }
-                if (event.getAction() == KeyEvent.ACTION_DOWN && downPressed == false) {
-                    downPressed = true;
-                } else if (event.getAction() == KeyEvent.ACTION_DOWN) {
-                    downPressed = false;
-                } else if (event.getAction() == KeyEvent.ACTION_UP && downPressed == true) {
-                    downPressed = false;
-                    mCallback.onUserCanceled();
-                }
-                return true;
-            }
-        });
-
-        final View space = mLayout.findViewById(R.id.space);
-        final View leftSpace = mLayout.findViewById(R.id.left_space);
-        final View rightSpace = mLayout.findViewById(R.id.right_space);
-        final Button negative = mLayout.findViewById(R.id.button2);
-        final Button positive = mLayout.findViewById(R.id.button1);
-
-        setDismissesDialog(space);
-        setDismissesDialog(leftSpace);
-        setDismissesDialog(rightSpace);
-
-        negative.setOnClickListener((View v) -> {
-            mCallback.onNegativePressed();
-        });
-
-        positive.setOnClickListener((View v) -> {
-            mCallback.onPositivePressed();
-        });
-
-        mLayout.setFocusableInTouchMode(true);
-        mLayout.requestFocus();
+    @Override
+    protected int getHintStringResourceId() {
+        return R.string.fingerprint_dialog_touch_sensor;
     }
 
     @Override
-    public void onAttachedToWindow() {
-        super.onAttachedToWindow();
-
-        final TextView title = mLayout.findViewById(R.id.title);
-        final TextView subtitle = mLayout.findViewById(R.id.subtitle);
-        final TextView description = mLayout.findViewById(R.id.description);
-        final Button negative = mLayout.findViewById(R.id.button2);
-        final Button positive = mLayout.findViewById(R.id.button1);
-
-        mDialog.getLayoutParams().width = (int) mDisplayWidth;
-
-        mLastState = STATE_NONE;
-        updateFingerprintIcon(STATE_FINGERPRINT);
-
-        title.setText(mBundle.getCharSequence(BiometricPrompt.KEY_TITLE));
-        title.setSelected(true);
-
-        final CharSequence subtitleText = mBundle.getCharSequence(BiometricPrompt.KEY_SUBTITLE);
-        if (TextUtils.isEmpty(subtitleText)) {
-            subtitle.setVisibility(View.GONE);
-        } else {
-            subtitle.setVisibility(View.VISIBLE);
-            subtitle.setText(subtitleText);
-        }
-
-        final CharSequence descriptionText = mBundle.getCharSequence(BiometricPrompt.KEY_DESCRIPTION);
-        if (TextUtils.isEmpty(descriptionText)) {
-            description.setVisibility(View.GONE);
-        } else {
-            description.setVisibility(View.VISIBLE);
-            description.setText(descriptionText);
-        }
-
-        negative.setText(mBundle.getCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT));
-
-        final CharSequence positiveText =
-                mBundle.getCharSequence(BiometricPrompt.KEY_POSITIVE_TEXT);
-        positive.setText(positiveText); // needs to be set for marquee to work
-        if (positiveText != null) {
-            positive.setVisibility(View.VISIBLE);
-        } else {
-            positive.setVisibility(View.GONE);
-        }
-
-        if (!mWasForceRemoved) {
-            // Dim the background and slide the dialog up
-            mDialog.setTranslationY(mAnimationTranslationOffset);
-            mLayout.setAlpha(0f);
-            postOnAnimation(mShowAnimationRunnable);
-        } else {
-            // Show the dialog immediately
-            mLayout.animate().cancel();
-            mDialog.animate().cancel();
-            mDialog.setAlpha(1.0f);
-            mDialog.setTranslationY(0);
-            mLayout.setAlpha(1.0f);
-        }
-        mWasForceRemoved = false;
+    protected int getAuthenticatedAccessibilityResourceId() {
+        return com.android.internal.R.string.fingerprint_authenticated;
     }
 
-    private void setDismissesDialog(View v) {
-        v.setClickable(true);
-        v.setOnTouchListener((View view, MotionEvent event) -> {
-            mCallback.onUserCanceled();
-            return true;
-        });
+    @Override
+    protected int getIconDescriptionResourceId() {
+        return R.string.accessibility_fingerprint_dialog_fingerprint_icon;
     }
 
-    public void startDismiss() {
-        mAnimatingAway = true;
-
-        final Runnable endActionRunnable = new Runnable() {
-            @Override
-            public void run() {
-                mWindowManager.removeView(FingerprintDialogView.this);
-                mAnimatingAway = false;
-            }
-        };
-
-        postOnAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mLayout.animate()
-                        .alpha(0f)
-                        .setDuration(ANIMATION_DURATION_AWAY)
-                        .setInterpolator(mLinearOutSlowIn)
-                        .withLayer()
-                        .start();
-                mDialog.animate()
-                        .translationY(mAnimationTranslationOffset)
-                        .setDuration(ANIMATION_DURATION_AWAY)
-                        .setInterpolator(mLinearOutSlowIn)
-                        .withLayer()
-                        .withEndAction(endActionRunnable)
-                        .start();
-            }
-        });
-    }
-
-    /**
-     * Force remove the window, cancelling any animation that's happening. This should only be
-     * called if we want to quickly show the dialog again (e.g. on rotation). Calling this method
-     * will cause the dialog to show without an animation the next time it's attached.
-     */
-    public void forceRemove() {
-        mLayout.animate().cancel();
-        mDialog.animate().cancel();
-        mWindowManager.removeView(FingerprintDialogView.this);
-        mAnimatingAway = false;
-        mWasForceRemoved = true;
-    }
-
-    public boolean isAnimatingAway() {
-        return mAnimatingAway;
-    }
-
-    public void setBundle(Bundle bundle) {
-        mBundle = bundle;
-    }
-
-    // Clears the temporary message and shows the help message.
-    private void handleClearMessage() {
-        updateFingerprintIcon(STATE_FINGERPRINT);
-        mErrorText.setText(R.string.fingerprint_dialog_touch_sensor);
-        mErrorText.setTextColor(mTextColor);
-    }
-
-    // Shows an error/help message
-    private void showTemporaryMessage(String message) {
-        mHandler.removeMessages(MSG_CLEAR_MESSAGE);
-        updateFingerprintIcon(STATE_FINGERPRINT_ERROR);
-        mErrorText.setText(message);
-        mErrorText.setTextColor(mErrorColor);
-        mErrorText.setContentDescription(message);
-        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CLEAR_MESSAGE),
-                BiometricPrompt.HIDE_DIALOG_DELAY);
-    }
-
-    public void showHelpMessage(String message) {
-        showTemporaryMessage(message);
-    }
-
-    public void showErrorMessage(String error) {
-        showTemporaryMessage(error);
-        mCallback.onErrorShown();
-    }
-
-    private void updateFingerprintIcon(int newState) {
-        Drawable icon  = getAnimationForTransition(mLastState, newState);
+    @Override
+    protected void updateIcon(int lastState, int newState) {
+        Drawable icon = getAnimationForTransition(lastState, newState);
 
         if (icon == null) {
             Log.e(TAG, "Animation not found");
@@ -342,25 +60,28 @@
                 ? (AnimatedVectorDrawable) icon
                 : null;
 
-        final ImageView fingerprint_icon = mLayout.findViewById(R.id.fingerprint_icon);
-        fingerprint_icon.setImageDrawable(icon);
+        final ImageView fingerprintIcon = getLayout().findViewById(R.id.biometric_icon);
+        fingerprintIcon.setImageDrawable(icon);
 
-        if (animation != null && shouldAnimateForTransition(mLastState, newState)) {
+        if (animation != null && shouldAnimateForTransition(lastState, newState)) {
             animation.forceAnimationOnUI();
             animation.start();
         }
+    }
 
-        mLastState = newState;
+    public FingerprintDialogView(Context context,
+            DialogViewCallback callback) {
+        super(context, callback);
     }
 
     private boolean shouldAnimateForTransition(int oldState, int newState) {
-        if (oldState == STATE_NONE && newState == STATE_FINGERPRINT) {
+        if (oldState == STATE_NONE && newState == STATE_AUTHENTICATING) {
             return false;
-        } else if (oldState == STATE_FINGERPRINT && newState == STATE_FINGERPRINT_ERROR) {
+        } else if (oldState == STATE_AUTHENTICATING && newState == STATE_ERROR) {
             return true;
-        } else if (oldState == STATE_FINGERPRINT_ERROR && newState == STATE_FINGERPRINT) {
+        } else if (oldState == STATE_ERROR && newState == STATE_AUTHENTICATING) {
             return true;
-        } else if (oldState == STATE_FINGERPRINT && newState == STATE_FINGERPRINT_AUTHENTICATED) {
+        } else if (oldState == STATE_AUTHENTICATING && newState == STATE_AUTHENTICATED) {
             // TODO(b/77328470): add animation when fingerprint is authenticated
             return false;
         }
@@ -369,32 +90,18 @@
 
     private Drawable getAnimationForTransition(int oldState, int newState) {
         int iconRes;
-        if (oldState == STATE_NONE && newState == STATE_FINGERPRINT) {
+        if (oldState == STATE_NONE && newState == STATE_AUTHENTICATING) {
             iconRes = R.drawable.fingerprint_dialog_fp_to_error;
-        } else if (oldState == STATE_FINGERPRINT && newState == STATE_FINGERPRINT_ERROR) {
+        } else if (oldState == STATE_AUTHENTICATING && newState == STATE_ERROR) {
             iconRes = R.drawable.fingerprint_dialog_fp_to_error;
-        } else if (oldState == STATE_FINGERPRINT_ERROR && newState == STATE_FINGERPRINT) {
+        } else if (oldState == STATE_ERROR && newState == STATE_AUTHENTICATING) {
             iconRes = R.drawable.fingerprint_dialog_error_to_fp;
-        } else if (oldState == STATE_FINGERPRINT && newState == STATE_FINGERPRINT_AUTHENTICATED) {
+        } else if (oldState == STATE_AUTHENTICATING && newState == STATE_AUTHENTICATED) {
             // TODO(b/77328470): add animation when fingerprint is authenticated
             iconRes = R.drawable.fingerprint_dialog_error_to_fp;
-        }
-        else {
+        } else {
             return null;
         }
         return mContext.getDrawable(iconRes);
     }
-
-    public WindowManager.LayoutParams getLayoutParams() {
-        final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
-                WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
-                PixelFormat.TRANSLUCENT);
-        lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
-        lp.setTitle("FingerprintDialogView");
-        lp.token = mWindowToken;
-        return lp;
-    }
-}
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
index d6a1cf0..5739c99 100644
--- a/packages/SystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
@@ -16,7 +16,6 @@
 package com.android.systemui.car;
 
 import android.content.Context;
-import android.service.notification.StatusBarNotification;
 
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.NotificationData;
@@ -41,7 +40,7 @@
     }
 
     @Override
-    public boolean shouldPeek(NotificationData.Entry entry, StatusBarNotification sbn) {
+    public boolean shouldHeadsUp(NotificationData.Entry entry) {
         // Because space is usually constrained in the auto use-case, there should not be a
         // pinned notification when the shade has been expanded. Ensure this by not pinning any
         // notification if the shade is already opened.
@@ -49,6 +48,6 @@
             return false;
         }
 
-        return super.shouldPeek(entry, sbn);
+        return super.shouldHeadsUp(entry);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index 6a29299..bb05980 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -48,7 +48,15 @@
     void onIgnoreTouchWhilePulsing(boolean ignore);
 
     interface Callback {
-        default void onNotificationHeadsUp() {}
+        /**
+         * Called when a high priority notification is added.
+         */
+        default void onNotificationAlerted() {}
+
+        /**
+         * Called when battery state or power save mode changes.
+         * @param active whether power save is active or not
+         */
         default void onPowerSaveChanged(boolean active) {}
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index 36b2347..c566460 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -16,11 +16,15 @@
 
 package com.android.systemui.doze;
 
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.hardware.Sensor;
 import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
+import android.os.Build;
 import android.os.Handler;
 import android.os.Trace;
 import android.os.UserHandle;
@@ -31,7 +35,12 @@
 /**
  * Controls the screen brightness when dozing.
  */
-public class DozeScreenBrightness implements DozeMachine.Part, SensorEventListener {
+public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachine.Part,
+        SensorEventListener {
+    protected static final String ACTION_AOD_BRIGHTNESS =
+            "com.android.systemui.doze.AOD_BRIGHTNESS";
+    protected static final String BRIGHTNESS_BUCKET = "brightness_bucket";
+
     private final Context mContext;
     private final DozeMachine.Service mDozeService;
     private final DozeHost mDozeHost;
@@ -40,36 +49,52 @@
     private final Sensor mLightSensor;
     private final int[] mSensorToBrightness;
     private final int[] mSensorToScrimOpacity;
+    private final boolean mDebuggable;
 
     private boolean mRegistered;
     private int mDefaultDozeBrightness;
     private boolean mPaused = false;
     private int mLastSensorValue = -1;
 
+    /**
+     * Debug value used for emulating various display brightness buckets:
+     *
+     * {@code am broadcast -p com.android.systemui -a com.android.systemui.doze.AOD_BRIGHTNESS
+     * --ei brightness_bucket 1}
+     */
+    private int mDebugBrightnessBucket = -1;
+
+    @VisibleForTesting
     public DozeScreenBrightness(Context context, DozeMachine.Service service,
             SensorManager sensorManager, Sensor lightSensor, DozeHost host,
             Handler handler, int defaultDozeBrightness, int[] sensorToBrightness,
-            int[] sensorToScrimOpacity) {
+            int[] sensorToScrimOpacity, boolean debuggable) {
         mContext = context;
         mDozeService = service;
         mSensorManager = sensorManager;
         mLightSensor = lightSensor;
         mDozeHost = host;
         mHandler = handler;
+        mDebuggable = debuggable;
 
         mDefaultDozeBrightness = defaultDozeBrightness;
         mSensorToBrightness = sensorToBrightness;
         mSensorToScrimOpacity = sensorToScrimOpacity;
+
+        if (mDebuggable) {
+            IntentFilter filter = new IntentFilter();
+            filter.addAction(ACTION_AOD_BRIGHTNESS);
+            mContext.registerReceiverAsUser(this, UserHandle.ALL, filter, null, null);
+        }
     }
 
-    @VisibleForTesting
     public DozeScreenBrightness(Context context, DozeMachine.Service service,
             SensorManager sensorManager, Sensor lightSensor, DozeHost host,
             Handler handler, AlwaysOnDisplayPolicy policy) {
         this(context, service, sensorManager, lightSensor, host, handler,
                 context.getResources().getInteger(
                         com.android.internal.R.integer.config_screenBrightnessDoze),
-                policy.screenBrightnessArray, policy.dimmingScrimArray);
+                policy.screenBrightnessArray, policy.dimmingScrimArray, Build.IS_DEBUGGABLE);
     }
 
     @Override
@@ -87,7 +112,7 @@
                 resetBrightnessToDefault();
                 break;
             case FINISH:
-                setLightSensorEnabled(false);
+                onDestroy();
                 break;
         }
         if (newState != DozeMachine.State.FINISH) {
@@ -95,6 +120,13 @@
         }
     }
 
+    private void onDestroy() {
+        setLightSensorEnabled(false);
+        if (mDebuggable) {
+            mContext.unregisterReceiver(this);
+        }
+    }
+
     @Override
     public void onSensorChanged(SensorEvent event) {
         Trace.beginSection("DozeScreenBrightness.onSensorChanged" + event.values[0]);
@@ -110,7 +142,9 @@
 
     private void updateBrightnessAndReady() {
         if (mRegistered) {
-            int brightness = computeBrightness(mLastSensorValue);
+            int sensorValue = mDebugBrightnessBucket == -1
+                    ? mLastSensorValue : mDebugBrightnessBucket;
+            int brightness = computeBrightness(sensorValue);
             boolean brightnessReady = brightness > 0;
             if (brightnessReady) {
                 mDozeService.setDozeScreenBrightness(clampToUserSetting(brightness));
@@ -125,7 +159,7 @@
                 scrimOpacity = 255;
             } else if (brightnessReady) {
                 // Only unblank scrim once brightness is ready.
-                scrimOpacity = computeScrimOpacity(mLastSensorValue);
+                scrimOpacity = computeScrimOpacity(sensorValue);
             }
             if (scrimOpacity >= 0) {
                 mDozeHost.setAodDimmingScrim(scrimOpacity / 255f);
@@ -184,4 +218,9 @@
         }
     }
 
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        mDebugBrightnessBucket = intent.getIntExtra(BRIGHTNESS_BUCKET, -1);
+        updateBrightnessAndReady();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 1589969..31548b9 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -409,7 +409,7 @@
 
     private DozeHost.Callback mHostCallback = new DozeHost.Callback() {
         @Override
-        public void onNotificationHeadsUp() {
+        public void onNotificationAlerted() {
             onNotification();
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelper.kt b/packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelper.kt
new file mode 100644
index 0000000..d1e5059
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelper.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.doze.util
+
+import android.util.MathUtils
+
+private const val MILLIS_PER_MINUTES = 1000 * 60f
+private const val BURN_IN_PREVENTION_PERIOD_Y = 521f
+private const val BURN_IN_PREVENTION_PERIOD_X = 83f
+
+/**
+ * Returns the translation offset that should be used to avoid burn in at
+ * the current time (in pixels.)
+ *
+ * @param amplitude Maximum translation that will be interpolated.
+ * @param xAxis If we're moving on X or Y.
+ */
+fun getBurnInOffset(amplitude: Int, xAxis: Boolean): Int {
+    return zigzag(System.currentTimeMillis() / MILLIS_PER_MINUTES,
+            amplitude.toFloat(),
+            if (xAxis) BURN_IN_PREVENTION_PERIOD_X else BURN_IN_PREVENTION_PERIOD_Y).toInt()
+}
+
+/**
+ * Implements a continuous, piecewise linear, periodic zig-zag function
+ *
+ * Can be thought of as a linear approximation of abs(sin(x)))
+ *
+ * @param period period of the function, ie. zigzag(x + period) == zigzag(x)
+ * @param amplitude maximum value of the function
+ * @return a value between 0 and amplitude
+ */
+private fun zigzag(x: Float, amplitude: Float, period: Float): Float {
+    val xprime = x % period / (period / 2)
+    val interpolationAmount = if (xprime <= 1) xprime else 2 - xprime
+    return MathUtils.lerp(0f, amplitude, interpolationAmount)
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index cc1b9e8..bde7f1b 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -55,6 +55,7 @@
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.ArraySet;
+import android.util.FeatureFlagUtils;
 import android.util.Log;
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
@@ -318,8 +319,8 @@
         ArraySet<String> addedKeys = new ArraySet<String>();
         mHasLogoutButton = false;
         mHasLockdownButton = false;
-        mSeparatedEmergencyButtonEnabled = Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.FASTER_EMERGENCY_PHONE_CALL_ENABLED, 0) != 0;
+        mSeparatedEmergencyButtonEnabled = FeatureFlagUtils
+                .isEnabled(mContext, FeatureFlagUtils.EMERGENCY_DIAL_SHORTCUTS);
         for (int i = 0; i < defaultActions.length; i++) {
             String actionKey = defaultActions[i];
             if (addedKeys.contains(actionKey)) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackRegistry.java b/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackRegistry.java
index 745f312..d833c16 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackRegistry.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackRegistry.java
@@ -19,9 +19,6 @@
 import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.systemui.Dependency;
 import com.android.systemui.UiOffloadThread;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-
 import java.util.ArrayList;
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 1655c01..4988f07 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -20,6 +20,9 @@
 import static android.view.Display.INVALID_DISPLAY;
 
 import static com.android.internal.telephony.IccCardConstants.State.ABSENT;
+import static com.android.internal.telephony.IccCardConstants.State.PIN_REQUIRED;
+import static com.android.internal.telephony.IccCardConstants.State.PUK_REQUIRED;
+import static com.android.internal.telephony.IccCardConstants.State.READY;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
 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;
@@ -30,7 +33,6 @@
 import android.app.AlarmManager;
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
-import android.hardware.biometrics.BiometricSourceType;
 import android.app.trust.TrustManager;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
@@ -38,6 +40,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.UserInfo;
+import android.hardware.biometrics.BiometricSourceType;
 import android.media.AudioManager;
 import android.media.SoundPool;
 import android.os.Bundle;
@@ -58,6 +61,7 @@
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.view.ViewGroup;
 import android.view.WindowManagerPolicyConstants;
 import android.view.animation.Animation;
@@ -70,21 +74,21 @@
 import com.android.internal.policy.IKeyguardExitCallback;
 import com.android.internal.policy.IKeyguardStateCallback;
 import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.util.LatencyTracker;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardConstants;
 import com.android.keyguard.KeyguardDisplayManager;
 import com.android.keyguard.KeyguardSecurityView;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.internal.util.LatencyTracker;
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.Dependency;
 import com.android.systemui.SystemUI;
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.UiOffloadThread;
 import com.android.systemui.classifier.FalsingManager;
-import com.android.systemui.statusbar.phone.NotificationPanelView;
 import com.android.systemui.statusbar.phone.BiometricUnlockController;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 
@@ -274,6 +278,12 @@
 
     private KeyguardUpdateMonitor mUpdateMonitor;
 
+    /**
+     * Last SIM state reported by the telephony system.
+     * Index is the slotId - in case of multiple SIM cards.
+     */
+    private final SparseArray<IccCardConstants.State> mLastSimStates = new SparseArray<>();
+
     private boolean mDeviceInteractive;
     private boolean mGoingToSleep;
 
@@ -450,6 +460,14 @@
                 }
             }
 
+            boolean simWasLocked;
+            synchronized (KeyguardViewMediator.this) {
+                IccCardConstants.State lastState = mLastSimStates.get(slotId);
+                simWasLocked = (lastState == PIN_REQUIRED || lastState == PUK_REQUIRED)
+                    && simState == READY;
+                mLastSimStates.append(slotId, simState);
+            }
+
             switch (simState) {
                 case NOT_READY:
                 case ABSENT:
@@ -503,6 +521,9 @@
                 case READY:
                     synchronized (KeyguardViewMediator.this) {
                         if (DEBUG_SIM_STATES) Log.d(TAG, "READY, reset state? " + mShowing);
+                        if (mShowing && simWasLocked) {
+                            resetStateLocked();
+                        }
                         mLockWhenSimRemoved = true;
                     }
                     break;
@@ -1917,6 +1938,12 @@
             mStatusBarManager = (StatusBarManager)
                     mContext.getSystemService(Context.STATUS_BAR_SERVICE);
         }
+
+        // TODO(b/113914868): investigation log for disappearing home button
+        Log.d(TAG, "adjustStatusBarLocked (b/113914868): mShowing=" + mShowing
+                + " mStatusBarManager=" + mStatusBarManager + " mOccluded="
+                + mOccluded + " isSecure=" + isSecure() + " force=" + forceHideHomeRecentsButtons);
+
         if (mStatusBarManager == null) {
             Log.w(TAG, "Could not get status bar manager");
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
index 0cedf98..74f7706 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
@@ -19,7 +19,6 @@
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
-import android.app.IActivityManager;
 import android.app.IActivityTaskManager;
 import android.app.KeyguardManager;
 import android.content.ComponentName;
@@ -29,11 +28,9 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.Log;
-
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
-import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.TaskStackChangeListener;
 
 public class WorkLockActivityController {
     private static final String TAG = WorkLockActivityController.class.getSimpleName();
@@ -111,7 +108,7 @@
         }
     }
 
-    private final SysUiTaskStackChangeListener mLockListener = new SysUiTaskStackChangeListener() {
+    private final TaskStackChangeListener mLockListener = new TaskStackChangeListener() {
         @Override
         public void onTaskProfileLocked(int taskId, int userId) {
             startWorkChallengeInTask(taskId, userId);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipUI.java b/packages/SystemUI/src/com/android/systemui/pip/PipUI.java
index b7164cb..864a6f9 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipUI.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipUI.java
@@ -21,11 +21,12 @@
 
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
-
+import android.os.UserHandle;
+import android.os.UserManager;
 import com.android.systemui.SystemUI;
-import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.component.ExpandPipEvent;
 import com.android.systemui.statusbar.CommandQueue;
-
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
@@ -47,8 +48,8 @@
         }
 
         // Ensure that we are the primary user's SystemUI.
-        final int processUser = SystemServicesProxy.getInstance(mContext).getProcessUser();
-        if (!SystemServicesProxy.getInstance(mContext).isSystemUser(processUser)) {
+        final int processUser = UserManager.get(mContext).getUserHandle();
+        if (processUser != UserHandle.USER_SYSTEM) {
             throw new IllegalStateException("Non-primary Pip component not currently supported.");
         }
 
@@ -58,6 +59,7 @@
         mPipManager.initialize(mContext);
 
         getComponent(CommandQueue.class).addCallbacks(this);
+        putComponent(PipUI.class, this);
     }
 
     @Override
@@ -65,6 +67,10 @@
         mPipManager.showPictureInPictureMenu();
     }
 
+    public void expandPip() {
+        EventBus.getDefault().send(new ExpandPipEvent());
+    }
+
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/ForegroundThread.java b/packages/SystemUI/src/com/android/systemui/pip/phone/ForegroundThread.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/recents/misc/ForegroundThread.java
rename to packages/SystemUI/src/com/android/systemui/pip/phone/ForegroundThread.java
index 784ac4e..9bf46bb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/ForegroundThread.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/ForegroundThread.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.recents.misc;
+package com.android.systemui.pip.phone;
 
 import android.os.Handler;
 import android.os.HandlerThread;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java
index 5547e2d..9ce2606 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java
@@ -19,21 +19,17 @@
 import android.content.Context;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
-import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.View.OnLayoutChangeListener;
-import android.view.ViewGroup;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
 import android.widget.FrameLayout;
-
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.shared.system.WindowManagerWrapper;
 
 public class PipDismissViewController {
 
@@ -59,7 +55,7 @@
         if (mDismissView == null) {
             // Determine sizes for the view
             final Rect stableInsets = new Rect();
-            SystemServicesProxy.getInstance(mContext).getStableInsets(stableInsets);
+            WindowManagerWrapper.getInstance().getStableInsets(stableInsets);
             final Point windowSize = new Point();
             mWindowManager.getDefaultDisplay().getRealSize(windowSize);
             final int gradientHeight = mContext.getResources().getDimensionPixelSize(
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index ee15655..04746c1 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -17,7 +17,6 @@
 package com.android.systemui.pip.phone;
 
 import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.WindowManager.INPUT_CONSUMER_PIP;
 
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
@@ -36,15 +35,15 @@
 import android.view.IPinnedStackListener;
 import android.view.IWindowManager;
 import android.view.WindowManagerGlobal;
-
+import com.android.systemui.Dependency;
+import com.android.systemui.UiOffloadThread;
 import com.android.systemui.pip.BasePipManager;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.component.ExpandPipEvent;
-import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
-import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.InputConsumerController;
-
+import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.shared.system.WindowManagerWrapper;
 import java.io.PrintWriter;
 
 /**
@@ -72,7 +71,7 @@
     /**
      * Handler for system task stack changes.
      */
-    SysUiTaskStackChangeListener mTaskStackListener = new SysUiTaskStackChangeListener() {
+    TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
         @Override
         public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
             mTouchHandler.onActivityPinned();
@@ -80,7 +79,9 @@
             mMenuController.onActivityPinned();
             mAppOpsListener.onActivityPinned(packageName);
 
-            SystemServicesProxy.getInstance(mContext).setPipVisibility(true);
+            Dependency.get(UiOffloadThread.class).submit(() -> {
+                WindowManagerWrapper.getInstance().setPipVisibility(true);
+            });
         }
 
         @Override
@@ -93,7 +94,9 @@
             mTouchHandler.onActivityUnpinned(topActivity);
             mAppOpsListener.onActivityUnpinned();
 
-            SystemServicesProxy.getInstance(mContext).setPipVisibility(topActivity != null);
+            Dependency.get(UiOffloadThread.class).submit(() -> {
+                WindowManagerWrapper.getInstance().setPipVisibility(topActivity != null);
+            });
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index f0ab046..ce7da79 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -30,7 +30,6 @@
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.app.ActivityManager.StackInfo;
-import android.app.ActivityTaskManager;
 import android.app.IActivityManager;
 import android.app.IActivityTaskManager;
 import android.content.Context;
@@ -43,14 +42,11 @@
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.animation.Interpolator;
-
 import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.policy.PipSnapAlgorithm;
-import com.android.systemui.recents.misc.ForegroundThread;
-import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.shared.system.WindowManagerWrapper;
 import com.android.systemui.statusbar.FlingAnimationUtils;
-
 import java.io.PrintWriter;
 
 /**
@@ -116,7 +112,7 @@
      */
     void onConfigurationChanged() {
         mSnapAlgorithm.onConfigurationChanged();
-        SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets);
+        WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index 020c550..43e9db7 100755
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -16,6 +16,11 @@
 
 package com.android.systemui.pip.tv;
 
+import static android.app.ActivityTaskManager.INVALID_STACK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.view.Display.DEFAULT_DISPLAY;
+
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityManager.StackInfo;
@@ -44,22 +49,17 @@
 import android.view.IPinnedStackListener;
 import android.view.IWindowManager;
 import android.view.WindowManagerGlobal;
-
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
+import com.android.systemui.UiOffloadThread;
 import com.android.systemui.pip.BasePipManager;
-import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
-import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
-
+import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.shared.system.WindowManagerWrapper;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
 
-import static android.app.ActivityTaskManager.INVALID_STACK_ID;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.view.Display.DEFAULT_DISPLAY;
-
 /**
  * Manages the picture-in-picture (PIP) UI and states.
  */
@@ -630,7 +630,7 @@
         return false;
     }
 
-    private SysUiTaskStackChangeListener mTaskStackListener = new SysUiTaskStackChangeListener() {
+    private TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
         @Override
         public void onTaskStackChanged() {
             if (DEBUG) Log.d(TAG, "onTaskStackChanged()");
@@ -754,7 +754,9 @@
     }
 
     private void updatePipVisibility(final boolean visible) {
-        SystemServicesProxy.getInstance(mContext).setPipVisibility(visible);
+        Dependency.get(UiOffloadThread.class).submit(() -> {
+            WindowManagerWrapper.getInstance().setPipVisibility(visible);
+        });
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
index d5541e9..7bc7e5f 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
@@ -33,6 +33,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.UserHandle;
+import android.util.ArraySet;
 import android.util.Log;
 import android.view.LayoutInflater;
 
@@ -41,7 +42,9 @@
 import com.android.systemui.plugins.VersionInfo.InvalidVersionException;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
+import com.android.systemui.R;
 
 public class PluginInstanceManager<T extends Plugin> {
 
@@ -63,17 +66,19 @@
     private final boolean isDebuggable;
     private final PackageManager mPm;
     private final PluginManagerImpl mManager;
+    private final ArraySet<String> mWhitelistedPlugins = new ArraySet<>();
 
     PluginInstanceManager(Context context, String action, PluginListener<T> listener,
             boolean allowMultiple, Looper looper, VersionInfo version, PluginManagerImpl manager) {
         this(context, context.getPackageManager(), action, listener, allowMultiple, looper, version,
-                manager, Build.IS_DEBUGGABLE);
+                manager, Build.IS_DEBUGGABLE,
+                context.getResources().getStringArray(R.array.config_pluginWhitelist));
     }
 
     @VisibleForTesting
     PluginInstanceManager(Context context, PackageManager pm, String action,
             PluginListener<T> listener, boolean allowMultiple, Looper looper, VersionInfo version,
-            PluginManagerImpl manager, boolean debuggable) {
+            PluginManagerImpl manager, boolean debuggable, String[] pluginWhitelist) {
         mMainHandler = new MainHandler(Looper.getMainLooper());
         mPluginHandler = new PluginHandler(looper);
         mManager = manager;
@@ -83,6 +88,7 @@
         mListener = listener;
         mAllowMultiple = allowMultiple;
         mVersion = version;
+        mWhitelistedPlugins.addAll(Arrays.asList(pluginWhitelist));
         isDebuggable = debuggable;
     }
 
@@ -294,9 +300,9 @@
         protected PluginInfo<T> handleLoadPlugin(ComponentName component) {
             // This was already checked, but do it again here to make extra extra sure, we don't
             // use these on production builds.
-            if (!isDebuggable) {
+            if (!isDebuggable && !mWhitelistedPlugins.contains(component.getPackageName())) {
                 // Never ever ever allow these on production builds, they are only for prototyping.
-                Log.d(TAG, "Somehow hit second debuggable check");
+                Log.w(TAG, "Plugin cannot be loaded on production build: " + component);
                 return null;
             }
             String pkg = component.getPackageName();
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
index 2a17e35..1cbf1fe 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
@@ -37,13 +37,12 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
-import android.util.Log.TerribleFailure;
-import android.util.Log.TerribleFailureHandler;
 import android.widget.Toast;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.systemui.Dependency;
+import com.android.systemui.R;
 import com.android.systemui.plugins.PluginInstanceManager.PluginContextWrapper;
 import com.android.systemui.plugins.PluginInstanceManager.PluginInfo;
 import com.android.systemui.plugins.annotations.ProvidesInterface;
@@ -53,13 +52,14 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.Thread.UncaughtExceptionHandler;
+import java.util.Arrays;
 import java.util.Map;
-
 /**
  * @see Plugin
  */
 public class PluginManagerImpl extends BroadcastReceiver implements PluginManager {
 
+    private static final String TAG = PluginManagerImpl.class.getSimpleName();
     static final String DISABLE_PLUGIN = "com.android.systemui.action.DISABLE_PLUGIN";
 
     private static PluginManager sInstance;
@@ -68,6 +68,7 @@
             = new ArrayMap<>();
     private final Map<String, ClassLoader> mClassLoaders = new ArrayMap<>();
     private final ArraySet<String> mOneShotPackages = new ArraySet<>();
+    private final ArraySet<String> mWhitelistedPlugins = new ArraySet<>();
     private final Context mContext;
     private final PluginInstanceManagerFactory mFactory;
     private final boolean isDebuggable;
@@ -79,30 +80,30 @@
     private boolean mWtfsSet;
 
     public PluginManagerImpl(Context context) {
-        this(context, new PluginInstanceManagerFactory(),
-                Build.IS_DEBUGGABLE, Thread.getUncaughtExceptionPreHandler());
+        this(context, new PluginInstanceManagerFactory(), Build.IS_DEBUGGABLE,
+                context.getResources().getStringArray(R.array.config_pluginWhitelist),
+                Thread.getUncaughtExceptionPreHandler());
     }
 
     @VisibleForTesting
     PluginManagerImpl(Context context, PluginInstanceManagerFactory factory, boolean debuggable,
-            UncaughtExceptionHandler defaultHandler) {
+            String[] whitelistedPlugins, UncaughtExceptionHandler defaultHandler) {
         mContext = context;
         mFactory = factory;
         mLooper = Dependency.get(Dependency.BG_LOOPER);
         isDebuggable = debuggable;
+        mWhitelistedPlugins.addAll(Arrays.asList(whitelistedPlugins));
         mPluginPrefs = new PluginPrefs(mContext);
 
         PluginExceptionHandler uncaughtExceptionHandler = new PluginExceptionHandler(
                 defaultHandler);
         Thread.setUncaughtExceptionPreHandler(uncaughtExceptionHandler);
-        if (isDebuggable) {
-            new Handler(mLooper).post(() -> {
-                // Plugin dependencies that don't have another good home can go here, but
-                // dependencies that have better places to init can happen elsewhere.
-                Dependency.get(PluginDependencyProvider.class)
-                        .allowPluginDependency(ActivityStarter.class);
-            });
-        }
+        new Handler(mLooper).post(() -> {
+            // Plugin dependencies that don't have another good home can go here, but
+            // dependencies that have better places to init can happen elsewhere.
+            Dependency.get(PluginDependencyProvider.class)
+                    .allowPluginDependency(ActivityStarter.class);
+        });
     }
 
     public <T extends Plugin> T getOneShotPlugin(Class<T> cls) {
@@ -117,10 +118,6 @@
     }
 
     public <T extends Plugin> T getOneShotPlugin(String action, Class<?> cls) {
-        if (!isDebuggable) {
-            // Never ever ever allow these on production builds, they are only for prototyping.
-            return null;
-        }
         if (Looper.myLooper() != Looper.getMainLooper()) {
             throw new RuntimeException("Must be called from UI thread");
         }
@@ -153,10 +150,6 @@
 
     public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
             Class cls, boolean allowMultiple) {
-        if (!isDebuggable) {
-            // Never ever ever allow these on production builds, they are only for prototyping.
-            return;
-        }
         mPluginPrefs.addAction(action);
         PluginInstanceManager p = mFactory.createPluginInstanceManager(mContext, action, listener,
                 allowMultiple, mLooper, cls, this);
@@ -166,10 +159,6 @@
     }
 
     public void removePluginListener(PluginListener<?> listener) {
-        if (!isDebuggable) {
-            // Never ever ever allow these on production builds, they are only for prototyping.
-            return;
-        }
         if (!mPluginMap.containsKey(listener)) return;
         mPluginMap.remove(listener).destroy();
         if (mPluginMap.size() == 0) {
@@ -261,6 +250,11 @@
     }
 
     public ClassLoader getClassLoader(String sourceDir, String pkg) {
+        if (!isDebuggable && !mWhitelistedPlugins.contains(pkg)) {
+            Log.w(TAG, "Cannot get class loader for non-whitelisted plugin. Src:" + sourceDir +
+                    ", pkg: " + pkg);
+            return null;
+        }
         if (mClassLoaders.containsKey(pkg)) {
             return mClassLoaders.get(pkg);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index ca1b489..fcd479c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -6,14 +6,12 @@
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
 import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
+
 import androidx.viewpager.widget.PagerAdapter;
 import androidx.viewpager.widget.ViewPager;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.LayoutInflater;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.animation.Interpolator;
@@ -41,14 +39,12 @@
         return t * t * t + 1.0f;
     };
 
-
     private final ArrayList<TileRecord> mTiles = new ArrayList<>();
     private final ArrayList<TilePage> mPages = new ArrayList<>();
 
     private PageIndicator mPageIndicator;
     private float mPageIndicatorPosition;
 
-    private int mNumPages;
     private PageListener mPageListener;
 
     private boolean mListening;
@@ -56,6 +52,7 @@
 
     private AnimatorSet mBounceAnimatorSet;
     private float mLastExpansion;
+    private boolean mDistributeTiles = false;
 
     public PagedTileLayout(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -122,7 +119,7 @@
 
     public void setPageIndicator(PageIndicator indicator) {
         mPageIndicator = indicator;
-        mPageIndicator.setNumPages(mNumPages);
+        mPageIndicator.setNumPages(mPages.size());
         mPageIndicator.setLocation(mPageIndicatorPosition);
     }
 
@@ -136,13 +133,15 @@
     @Override
     public void addTile(TileRecord tile) {
         mTiles.add(tile);
-        postDistributeTiles();
+        mDistributeTiles = true;
+        requestLayout();
     }
 
     @Override
     public void removeTile(TileRecord tile) {
         if (mTiles.remove(tile)) {
-            postDistributeTiles();
+            mDistributeTiles = true;
+            requestLayout();
         }
     }
 
@@ -175,44 +174,50 @@
         mPageListener = listener;
     }
 
-    private void postDistributeTiles() {
-        removeCallbacks(mDistribute);
-        post(mDistribute);
-    }
-
     private void distributeTiles() {
+        emptyAndInflateOrRemovePages();
+
+        final int tileCount = mPages.get(0).maxTiles();
         if (DEBUG) Log.d(TAG, "Distributing tiles");
-        final int NP = mPages.size();
-        for (int i = 0; i < NP; i++) {
-            mPages.get(i).removeAllViews();
-        }
         int index = 0;
         final int NT = mTiles.size();
         for (int i = 0; i < NT; i++) {
             TileRecord tile = mTiles.get(i);
-            if (mPages.get(index).isFull()) {
-                if (++index == mPages.size()) {
-                    if (DEBUG) Log.d(TAG, "Adding page for "
-                            + tile.tile.getClass().getSimpleName());
-                    mPages.add((TilePage) LayoutInflater.from(getContext())
-                            .inflate(R.layout.qs_paged_page, this, false));
-                }
+            if (mPages.get(index).mRecords.size() == tileCount) index++;
+            if (DEBUG) {
+                Log.d(TAG, "Adding " + tile.tile.getClass().getSimpleName() + " to "
+                        + index);
             }
-            if (DEBUG) Log.d(TAG, "Adding " + tile.tile.getClass().getSimpleName() + " to "
-                    + index);
             mPages.get(index).addTile(tile);
         }
-        if (mNumPages != index + 1) {
-            mNumPages = index + 1;
-            while (mPages.size() > mNumPages) {
-                mPages.remove(mPages.size() - 1);
-            }
-            if (DEBUG) Log.d(TAG, "Size: " + mNumPages);
-            mPageIndicator.setNumPages(mNumPages);
-            setAdapter(mAdapter);
-            mAdapter.notifyDataSetChanged();
-            setCurrentItem(0, false);
+    }
+
+    private void emptyAndInflateOrRemovePages() {
+        final int nTiles = mTiles.size();
+        int numPages = nTiles / mPages.get(0).maxTiles();
+        // Add one more not full page if needed
+        numPages += (nTiles % mPages.get(0).maxTiles() == 0 ? 0 : 1);
+
+        final int NP = mPages.size();
+        for (int i = 0; i < NP; i++) {
+            mPages.get(i).removeAllViews();
         }
+        if (NP == numPages) {
+            return;
+        }
+        while (mPages.size() < numPages) {
+            if (DEBUG) Log.d(TAG, "Adding page");
+            mPages.add((TilePage) LayoutInflater.from(getContext())
+                    .inflate(R.layout.qs_paged_page, this, false));
+        }
+        while (mPages.size() > numPages) {
+            if (DEBUG) Log.d(TAG, "Removing page");
+            mPages.remove(mPages.size() - 1);
+        }
+        mPageIndicator.setNumPages(mPages.size());
+        setAdapter(mAdapter);
+        mAdapter.notifyDataSetChanged();
+        setCurrentItem(0, false);
     }
 
     @Override
@@ -222,20 +227,39 @@
         setPadding(0, 0, 0,
                 getContext().getResources().getDimensionPixelSize(
                         R.dimen.qs_paged_tile_layout_padding_bottom));
-
         boolean changed = false;
         for (int i = 0; i < mPages.size(); i++) {
             changed |= mPages.get(i).updateResources();
         }
         if (changed) {
-            distributeTiles();
+            mDistributeTiles = true;
+            requestLayout();
         }
         return changed;
     }
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+
+        final int nTiles = mTiles.size();
+        if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
+
+            // Only change the pages if the number of rows or columns (from updateResources) has
+            // changed or the tiles have changed
+            if (mPages.get(0).updateMaxRows(heightMeasureSpec, nTiles) || mDistributeTiles) {
+                mDistributeTiles = false;
+                distributeTiles();
+            }
+
+            final int nRows = mPages.get(0).mRows;
+            for (int i = 0; i < mPages.size(); i++) {
+                TilePage t = mPages.get(i);
+                t.mRows = nRows;
+            }
+        }
+
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
         // The ViewPager likes to eat all of the space, instead force it to wrap to the max height
         // of the pages.
         int maxHeight = 0;
@@ -249,13 +273,6 @@
         setMeasuredDimension(getMeasuredWidth(), maxHeight + getPaddingBottom());
     }
 
-    private final Runnable mDistribute = new Runnable() {
-        @Override
-        public void run() {
-            distributeTiles();
-        }
-    };
-
     public int getColumnCount() {
         if (mPages.size() == 0) return 0;
         return mPages.get(0).mColumns;
@@ -346,33 +363,17 @@
             };
 
     public static class TilePage extends TileLayout {
-        private int mMaxRows = 3;
+
         public TilePage(Context context, AttributeSet attrs) {
             super(context, attrs);
-            updateResources();
-        }
-
-        @Override
-        public boolean updateResources() {
-            final int rows = getRows();
-            boolean changed = rows != mMaxRows;
-            if (changed) {
-                mMaxRows = rows;
-                requestLayout();
-            }
-            return super.updateResources() || changed;
-        }
-
-        private int getRows() {
-            return Math.max(1, getResources().getInteger(R.integer.quick_settings_num_rows));
-        }
-
-        public void setMaxRows(int maxRows) {
-            mMaxRows = maxRows;
         }
 
         public boolean isFull() {
-            return mRecords.size() >= mColumns * mMaxRows;
+            return mRecords.size() >= mColumns * mRows;
+        }
+
+        public int maxTiles() {
+            return mColumns * mRows;
         }
     }
 
@@ -391,6 +392,9 @@
                 position = mPages.size() - 1 - position;
             }
             ViewGroup view = mPages.get(position);
+            if (view.getParent() != null) {
+                container.removeView(view);
+            }
             container.addView(view);
             updateListening();
             return view;
@@ -398,7 +402,7 @@
 
         @Override
         public int getCount() {
-            return mNumPages;
+            return mPages.size();
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index feff5d4..1451e71 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -23,6 +23,7 @@
 import android.content.res.Configuration;
 import android.graphics.Point;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.View;
 import android.widget.FrameLayout;
 
@@ -91,15 +92,24 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        // Since we control our own bottom, be whatever size we want.
-        // Otherwise the QSPanel ends up with 0 height when the window is only the
-        // size of the status bar.
-        mQSPanel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(
-                MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.UNSPECIFIED));
+        // QSPanel will show as many rows as it can (up to TileLayout.MAX_ROWS) such that the
+        // bottom and footer are inside the screen.
+        Configuration config = getResources().getConfiguration();
+        boolean navBelow = config.smallestScreenWidthDp >= 600
+                || config.orientation != Configuration.ORIENTATION_LANDSCAPE;
+        MarginLayoutParams layoutParams = (MarginLayoutParams) mQSPanel.getLayoutParams();
+
+        // The footer is pinned to the bottom of QSPanel (same bottoms), therefore we don't need to
+        // subtract its height. We do not care if the collapsed notifications fit in the screen.
+        int maxQs = getDisplayHeight() - layoutParams.topMargin - layoutParams.bottomMargin
+                - getPaddingBottom();
+        if (navBelow) {
+            maxQs -= getResources().getDimensionPixelSize(R.dimen.navigation_bar_height);
+        }
+        mQSPanel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(maxQs, MeasureSpec.AT_MOST));
         int width = mQSPanel.getMeasuredWidth();
-        LayoutParams layoutParams = (LayoutParams) mQSPanel.getLayoutParams();
         int height = layoutParams.topMargin + layoutParams.bottomMargin
-                + mQSPanel.getMeasuredHeight();
+                + mQSPanel.getMeasuredHeight() + getPaddingBottom();
         super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index c36cdf6..79e5086 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -256,7 +256,7 @@
     public void setExpanded(boolean expanded) {
         if (DEBUG) Log.d(TAG, "setExpanded " + expanded);
         mQsExpanded = expanded;
-        mQSPanel.setListening(mListening && mQsExpanded);
+        mQSPanel.setListening(mListening, mQsExpanded);
         updateQsState();
     }
 
@@ -287,8 +287,7 @@
         mListening = listening;
         mHeader.setListening(listening);
         mFooter.setListening(listening);
-        mQSPanel.setListening(mListening && mQsExpanded);
-        mQSPanel.getFooter().setListening(listening);
+        mQSPanel.setListening(mListening, mQsExpanded);
     }
 
     @Override
@@ -365,7 +364,11 @@
                 .setListener(new AnimatorListenerAdapter() {
                     @Override
                     public void onAnimationEnd(Animator animation) {
-                        getView().animate().setListener(null);
+                        if (getView() != null) {
+                            // The view could be destroyed before the animation completes when
+                            // switching users.
+                            getView().animate().setListener(null);
+                        }
                         mHeaderAnimating = false;
                         updateQsState();
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 7a57fdd..8b2e1d5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -353,12 +353,21 @@
         if (mListening) {
             refreshAllTiles();
         }
-        if (mBrightnessView.getVisibility() == View.VISIBLE) {
-            if (listening) {
-                mBrightnessController.registerCallbacks();
-            } else {
-                mBrightnessController.unregisterCallbacks();
-            }
+    }
+
+    public void setListening(boolean listening, boolean expanded) {
+        setListening(listening && expanded);
+        getFooter().setListening(listening);
+        // Set the listening as soon as the QS fragment starts listening regardless of the expansion,
+        // so it will update the current brightness before the slider is visible.
+        setBrightnessListening(listening);
+    }
+
+    public void setBrightnessListening(boolean listening) {
+        if (listening) {
+            mBrightnessController.registerCallbacks();
+        } else {
+            mBrightnessController.unregisterCallbacks();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index c67165e..01ff72e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -24,10 +24,12 @@
     protected int mCellMarginHorizontal;
     protected int mCellMarginVertical;
     protected int mSidePadding;
+    protected int mRows = 1;
 
     protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
     private int mCellMarginTop;
     private boolean mListening;
+    protected int mMaxAllowedRows = 3;
 
     public TileLayout(Context context) {
         this(context, null);
@@ -86,6 +88,7 @@
         mCellMarginVertical= res.getDimensionPixelSize(R.dimen.qs_tile_margin_vertical);
         mCellMarginTop = res.getDimensionPixelSize(R.dimen.qs_tile_margin_top);
         mSidePadding = res.getDimensionPixelOffset(R.dimen.qs_tile_layout_margin_side);
+        mMaxAllowedRows = Math.max(1, getResources().getInteger(R.integer.quick_settings_max_rows));
         if (mColumns != columns) {
             mColumns = columns;
             requestLayout();
@@ -96,10 +99,16 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        // If called with AT_MOST, it will limit the number of rows. If called with UNSPECIFIED
+        // it will show all its tiles. In this case, the tiles have to be entered before the
+        // container is measured. Any change in the tiles, should trigger a remeasure.
         final int numTiles = mRecords.size();
         final int width = MeasureSpec.getSize(widthMeasureSpec)
                 - getPaddingStart() - getPaddingEnd();
-        final int numRows = (numTiles + mColumns - 1) / mColumns;
+        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+        if (heightMode == MeasureSpec.UNSPECIFIED) {
+            mRows = (numTiles + mColumns - 1) / mColumns;
+        }
         mCellWidth = (width - mSidePadding * 2 - (mCellMarginHorizontal * mColumns)) / mColumns;
 
         // Measure each QS tile.
@@ -112,13 +121,35 @@
 
         // Only include the top margin in our measurement if we have more than 1 row to show.
         // Otherwise, don't add the extra margin buffer at top.
-        int height = (mCellHeight + mCellMarginVertical) * numRows +
-                (numRows != 0 ? (mCellMarginTop - mCellMarginVertical) : 0);
+        int height = (mCellHeight + mCellMarginVertical) * mRows +
+                (mRows != 0 ? (mCellMarginTop - mCellMarginVertical) : 0);
         if (height < 0) height = 0;
 
         setMeasuredDimension(width, height);
     }
 
+    /**
+     * Determines the maximum number of rows that can be shown based on height. Clips at a minimum
+     * of 1 and a maximum of mMaxAllowedRows.
+     *
+     * @param heightMeasureSpec Available height.
+     * @param tilesCount Upper limit on the number of tiles to show. to prevent empty rows.
+     */
+    public boolean updateMaxRows(int heightMeasureSpec, int tilesCount) {
+        final int availableHeight = MeasureSpec.getSize(heightMeasureSpec) - mCellMarginTop;
+        final int previousRows = mRows;
+        mRows = availableHeight / (mCellHeight + mCellMarginVertical);
+        if (mRows >= mMaxAllowedRows) {
+            mRows = mMaxAllowedRows;
+        } else if (mRows <= 1) {
+            mRows = 1;
+        }
+        if (mRows > (tilesCount + mColumns - 1) / mColumns) {
+            mRows = (tilesCount + mColumns - 1) / mColumns;
+        }
+        return previousRows != mRows;
+    }
+
     @Override
     public boolean hasOverlappingRendering() {
         return false;
@@ -135,7 +166,8 @@
         int column = 0;
 
         // Layout each QS tile.
-        for (int i = 0; i < numRecords; i++, column++) {
+        final int tilesToLayout = Math.min(numRecords, mRows * mColumns);
+        for (int i = 0; i < tilesToLayout; i++, column++) {
             // If we reached the last column available to layout a tile, wrap back to the next row.
             if (column == mColumns) {
                 column = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 3f7eeb8..dc17dd8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -69,6 +69,7 @@
     private final QSDetailClipper mClipper;
     private final LightBarController mLightBarController;
     private final TileQueryHelper mTileQueryHelper;
+    private final View mTransparentView;
 
     private boolean isShown;
     private QSTileHost mHost;
@@ -108,6 +109,7 @@
         mToolbar.getNavigationIcon().setTint(accentColor);
         mToolbar.getOverflowIcon().setTint(accentColor);
         mRecyclerView = findViewById(android.R.id.list);
+        mTransparentView = findViewById(R.id.customizer_transparent_view);
         mTileAdapter = new TileAdapter(getContext());
         mTileQueryHelper = new TileQueryHelper(context, mTileAdapter);
         mRecyclerView.setAdapter(mTileAdapter);
@@ -127,6 +129,14 @@
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
         updateNavBackDrop(newConfig);
+        updateResources();
+    }
+
+    private void updateResources() {
+        LayoutParams lp = (LayoutParams) mTransparentView.getLayoutParams();
+        lp.height = mContext.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.quick_qs_offset_height);
+        mTransparentView.setLayoutParams(lp);
     }
 
     private void updateNavBackDrop(Configuration newConfig) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
index 12daff1..9edd65e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
@@ -25,6 +25,7 @@
 import android.graphics.drawable.Drawable;
 import android.nfc.NfcAdapter;
 import android.provider.Settings;
+import android.service.quicksettings.Tile;
 import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
@@ -77,6 +78,9 @@
 
     @Override
     protected void handleClick() {
+        if (getAdapter() == null) {
+            return;
+        }
         if (!getAdapter().isEnabled()) {
             getAdapter().enable();
         } else {
@@ -96,13 +100,13 @@
 
     @Override
     protected void handleUpdateState(BooleanState state, Object arg) {
-        final Drawable mEnable = mContext.getDrawable(R.drawable.ic_qs_nfc_enabled);
-        final Drawable mDisable = mContext.getDrawable(R.drawable.ic_qs_nfc_disabled);
-
-        if (getAdapter() == null) return;
-        state.value = getAdapter().isEnabled();
+        state.value = getAdapter() != null && getAdapter().isEnabled();
+        state.state = getAdapter() == null
+                ? Tile.STATE_UNAVAILABLE
+                : state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+        state.icon = ResourceIcon.get(
+                state.value ? R.drawable.ic_qs_nfc_enabled : R.drawable.ic_qs_nfc_disabled);
         state.label = mContext.getString(R.string.quick_settings_nfc_label);
-        state.icon = new DrawableIcon(state.value ? mEnable : mDisable);
         state.expandedAccessibilityClassName = Switch.class.getName();
         state.contentDescription = state.label;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl b/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
index fc1831d..90c1099 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
+++ b/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
@@ -31,8 +31,7 @@
     void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
     void toggleRecents(int recentsGrowTarget);
     void onConfigurationChanged();
-    void splitPrimaryTask(int topTaskId, int dragMode, int stackCreateMode,
-            in Rect initialBounds);
+    void splitPrimaryTask(int topTaskId, int stackCreateMode, in Rect initialBounds);
     void onDraggingInRecents(float distanceFromTop);
     void onDraggingInRecentsEnded(float velocity);
     void showCurrentUserToast(int msgResId, int msgLength);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl b/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
index 58d8d8f..e977144 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
+++ b/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
@@ -29,7 +29,7 @@
     void updateRecentsVisibility(boolean visible);
     void startScreenPinning(int taskId);
     void sendRecentsDrawnEvent();
-    void sendDockingTopTaskEvent(int dragMode, in Rect initialRect);
+    void sendDockingTopTaskEvent(in Rect initialRect);
     void sendLaunchRecentsEvent();
     void sendDockedFirstAnimationFrameEvent();
     void setWaitingForTransitionStartEvent(boolean waitingForTransitionStart);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 8bb3c02..74f6c2d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -53,6 +53,7 @@
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
 import com.android.systemui.SystemUIApplication;
+import com.android.systemui.recents.events.ui.RecentsGrowingEvent;
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.SystemUI;
 import com.android.systemui.recents.events.EventBus;
@@ -248,6 +249,10 @@
         mImpl.onBootCompleted();
     }
 
+    public void growRecents() {
+        EventBus.getDefault().send(new RecentsGrowingEvent());
+    }
+
     /**
      * Shows the Recents.
      */
@@ -463,7 +468,7 @@
     }
 
     @Override
-    public boolean splitPrimaryTask(int dragMode, int stackCreateMode, Rect initialBounds,
+    public boolean splitPrimaryTask(int stackCreateMode, Rect initialBounds,
             int metricsDockAction) {
         // Ensure the device has been provisioned before allowing the user to interact with
         // recents
@@ -495,16 +500,15 @@
                             runningTask.topActivity.flattenToShortString());
                 }
                 if (sSystemServicesProxy.isSystemUser(currentUser)) {
-                    mImpl.splitPrimaryTask(runningTask.id, dragMode, stackCreateMode,
-                            initialBounds);
+                    mImpl.splitPrimaryTask(runningTask.id, stackCreateMode, initialBounds);
                 } else {
                     if (mSystemToUserCallbacks != null) {
                         IRecentsNonSystemUserCallbacks callbacks =
                                 mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
                         if (callbacks != null) {
                             try {
-                                callbacks.splitPrimaryTask(runningTask.id, dragMode,
-                                        stackCreateMode, initialBounds);
+                                callbacks.splitPrimaryTask(runningTask.id, stackCreateMode,
+                                        initialBounds);
                             } catch (RemoteException e) {
                                 Log.e(TAG, "Callback failed", e);
                             }
@@ -552,53 +556,6 @@
         }
     }
 
-    @Override
-    public void onDraggingInRecents(float distanceFromTop) {
-        if (sSystemServicesProxy.isSystemUser(mDraggingInRecentsCurrentUser)) {
-            mImpl.onDraggingInRecents(distanceFromTop);
-        } else {
-            if (mSystemToUserCallbacks != null) {
-                IRecentsNonSystemUserCallbacks callbacks =
-                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser(
-                                mDraggingInRecentsCurrentUser);
-                if (callbacks != null) {
-                    try {
-                        callbacks.onDraggingInRecents(distanceFromTop);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Callback failed", e);
-                    }
-                } else {
-                    Log.e(TAG, "No SystemUI callbacks found for user: "
-                            + mDraggingInRecentsCurrentUser);
-                }
-            }
-        }
-    }
-
-    @Override
-    public void onDraggingInRecentsEnded(float velocity) {
-        if (sSystemServicesProxy.isSystemUser(mDraggingInRecentsCurrentUser)) {
-            mImpl.onDraggingInRecentsEnded(velocity);
-        } else {
-            if (mSystemToUserCallbacks != null) {
-                IRecentsNonSystemUserCallbacks callbacks =
-                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser(
-                                mDraggingInRecentsCurrentUser);
-                if (callbacks != null) {
-                    try {
-                        callbacks.onDraggingInRecentsEnded(velocity);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Callback failed", e);
-                    }
-                } else {
-                    Log.e(TAG, "No SystemUI callbacks found for user: "
-                            + mDraggingInRecentsCurrentUser);
-                }
-            }
-        }
-    }
-
-    @Override
     public void showNextAffiliatedTask() {
         // Ensure the device has been provisioned before allowing the user to interact with
         // recents
@@ -609,7 +566,6 @@
         mImpl.showNextAffiliatedTask();
     }
 
-    @Override
     public void showPrevAffiliatedTask() {
         // Ensure the device has been provisioned before allowing the user to interact with
         // recents
@@ -686,7 +642,12 @@
     public final void onBusEvent(DockedFirstAnimationFrameEvent event) {
         SystemServicesProxy ssp = Recents.getSystemServices();
         int processUser = ssp.getProcessUser();
-        if (!ssp.isSystemUser(processUser)) {
+        if (ssp.isSystemUser(processUser)) {
+            final Divider divider = getComponent(Divider.class);
+            if (divider != null) {
+                divider.onDockedFirstAnimationFrame();
+            }
+        } else {
             postToSystemUser(new Runnable() {
                 @Override
                 public void run() {
@@ -723,7 +684,12 @@
 
     public final void onBusEvent(final RecentsDrawnEvent event) {
         int processUser = sSystemServicesProxy.getProcessUser();
-        if (!sSystemServicesProxy.isSystemUser(processUser)) {
+        if (sSystemServicesProxy.isSystemUser(processUser)) {
+            final Divider divider = getComponent(Divider.class);
+            if (divider != null) {
+                divider.onRecentsDrawn();
+            }
+        } else {
             postToSystemUser(new Runnable() {
                 @Override
                 public void run() {
@@ -739,13 +705,17 @@
 
     public final void onBusEvent(final DockedTopTaskEvent event) {
         int processUser = sSystemServicesProxy.getProcessUser();
-        if (!sSystemServicesProxy.isSystemUser(processUser)) {
+        if (sSystemServicesProxy.isSystemUser(processUser)) {
+            final Divider divider = getComponent(Divider.class);
+            if (divider != null) {
+                divider.onDockedTopTask();
+            }
+        } else {
             postToSystemUser(new Runnable() {
                 @Override
                 public void run() {
                     try {
-                        mUserToSystemCallbacks.sendDockingTopTaskEvent(event.dragMode,
-                                event.initialRect);
+                        mUserToSystemCallbacks.sendDockingTopTaskEvent(event.initialRect);
                     } catch (RemoteException e) {
                         Log.e(TAG, "Callback failed", e);
                     }
@@ -756,7 +726,12 @@
 
     public final void onBusEvent(final RecentsActivityStartingEvent event) {
         int processUser = sSystemServicesProxy.getProcessUser();
-        if (!sSystemServicesProxy.isSystemUser(processUser)) {
+        if (sSystemServicesProxy.isSystemUser(processUser)) {
+            final Divider divider = getComponent(Divider.class);
+            if (divider != null) {
+                divider.onRecentsActivityStarting();
+            }
+        } else {
             postToSystemUser(new Runnable() {
                 @Override
                 public void run() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 63a65d0..d95c731 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -49,6 +49,7 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.OverviewProxyService;
 import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.pip.phone.ForegroundThread;
 import com.google.android.collect.Lists;
 
 import com.android.internal.logging.MetricsLogger;
@@ -72,7 +73,6 @@
 import com.android.systemui.recents.events.ui.DraggingInRecentsEvent;
 import com.android.systemui.recents.events.ui.TaskSnapshotChangedEvent;
 import com.android.systemui.recents.misc.DozeTrigger;
-import com.android.systemui.recents.misc.ForegroundThread;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
 import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
@@ -690,14 +690,13 @@
         showRelativeAffiliatedTask(false);
     }
 
-    public void splitPrimaryTask(int taskId, int dragMode, int stackCreateMode,
-            Rect initialBounds) {
+    public void splitPrimaryTask(int taskId, int stackCreateMode, Rect initialBounds) {
         SystemServicesProxy ssp = Recents.getSystemServices();
 
         // Make sure we inform DividerView before we actually start the activity so we can change
         // the resize mode already.
         if (ssp.setTaskWindowingModeSplitScreenPrimary(taskId, stackCreateMode, initialBounds)) {
-            EventBus.getDefault().send(new DockedTopTaskEvent(dragMode, initialBounds));
+            EventBus.getDefault().send(new DockedTopTaskEvent(initialBounds));
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
index beec4b3..a1da785 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
@@ -87,12 +87,11 @@
     }
 
     @Override
-    public void splitPrimaryTask(int topTaskId, int dragMode, int stackCreateMode,
-            Rect initialBounds) throws RemoteException {
+    public void splitPrimaryTask(int topTaskId, int stackCreateMode, Rect initialBounds)
+            throws RemoteException {
         SomeArgs args = SomeArgs.obtain();
         args.argi1 = topTaskId;
-        args.argi2 = dragMode;
-        args.argi3 = stackCreateMode;
+        args.argi2 = stackCreateMode;
         args.arg1 = initialBounds;
         mHandler.sendMessage(mHandler.obtainMessage(MSG_DOCK_TOP_TASK, args));
     }
@@ -141,7 +140,7 @@
                     break;
                 case MSG_DOCK_TOP_TASK:
                     args = (SomeArgs) msg.obj;
-                    mImpl.splitPrimaryTask(args.argi1, args.argi2, args.argi3 = 0,
+                    mImpl.splitPrimaryTask(args.argi1, args.argi2 = 0,
                             (Rect) args.arg1);
                     break;
                 case MSG_ON_DRAGGING_IN_RECENTS:
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
index ff1f7dc..c5e9f04 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
@@ -26,13 +26,13 @@
 
 import com.android.systemui.EventLogConstants;
 import com.android.systemui.EventLogTags;
+import com.android.systemui.pip.phone.ForegroundThread;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent;
 import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
 import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
 import com.android.systemui.recents.events.component.SetWaitingForTransitionStartEvent;
 import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
-import com.android.systemui.recents.misc.ForegroundThread;
 
 /**
  * An implementation of the system user's Recents interface to be called remotely by secondary
@@ -99,8 +99,8 @@
     }
 
     @Override
-    public void sendDockingTopTaskEvent(int dragMode, Rect initialRect) throws RemoteException {
-        EventBus.getDefault().post(new DockedTopTaskEvent(dragMode, initialRect));
+    public void sendDockingTopTaskEvent(Rect initialRect) throws RemoteException {
+        EventBus.getDefault().post(new DockedTopTaskEvent(initialRect));
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
index d7abb38..177362c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
@@ -16,23 +16,16 @@
 
 package com.android.systemui.recents.events;
 
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.util.Log;
-import android.util.MutableBoolean;
 
 import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
-import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
@@ -117,11 +110,7 @@
  * <p>
  * Currently, there is a single EventBus that handles {@link EventBus.Event}s for each subscriber
  * on the main application thread.  Publishers can send() events to synchronously call subscribers
- * of that event, or post() events to be processed in the next run of the {@link Looper}.  In
- * addition, the EventBus supports sending and handling {@link EventBus.InterprocessEvent}s
- * (within the same package) implemented using standard {@link BroadcastReceiver} mechanism.
- * Interprocess events must be posted using postInterprocess() to ensure that it is dispatched
- * correctly across processes.
+ * of that event, or post() events to be processed in the next run of the {@link Looper}.
  *
  * <p>
  * Subscribers must be registered with a particular EventBus before they will receive events, and
@@ -135,26 +124,12 @@
  * <li>Methods must take one parameter, of class type deriving from {@link EventBus.Event}
  * </ul>
  *
- * <p>
- * Interprocess-Event method signature:<ul>
- * <li>Methods must be public final
- * <li>Methods must return void
- * <li>Methods must be called "onInterprocessBusEvent"
- * <li>Methods must take one parameter, of class type deriving from {@link EventBus.InterprocessEvent}
- * </ul>
- * </p>
- *
  * </p>
  * Each subscriber can be registered with a given priority (default 1), and events will be dispatch
  * in decreasing order of priority.  For subscribers with the same priority, events will be
  * dispatched by latest registration time to earliest.
  *
  * <p>
- * Interprocess events must extend {@link EventBus.InterprocessEvent}, have a constructor which
- * takes a {@link Bundle} and implement toBundle().  This allows us to serialize events to be sent
- * across processes.
- *
- * <p>
  * Caveats:<ul>
  * <li>The EventBus keeps a {@link WeakReference} to the publisher to prevent memory leaks, so
  * there must be another strong reference to the publisher for it to not get garbage-collected and
@@ -201,7 +176,7 @@
  * result?
  * </p>
  */
-public class EventBus extends BroadcastReceiver {
+public class EventBus {
 
     private static final String TAG = "EventBus";
     private static final boolean DEBUG_TRACE_ALL = false;
@@ -314,35 +289,6 @@
     }
 
     /**
-     * An inter-process event super class that allows us to track user state across subscriber
-     * invocations.
-     */
-    public static class InterprocessEvent extends Event {
-        private static final String EXTRA_USER = "_user";
-
-        // The user which this event originated from
-        public final int user;
-
-        // Only accessible from derived events
-        protected InterprocessEvent(int user) {
-            this.user = user;
-        }
-
-        /**
-         * Called from the event bus
-         */
-        protected InterprocessEvent(Bundle b) {
-            user = b.getInt(EXTRA_USER);
-        }
-
-        protected Bundle toBundle() {
-            Bundle b = new Bundle();
-            b.putInt(EXTRA_USER, user);
-            return b;
-        }
-    }
-
-    /**
      * Proguard must also know, and keep, all methods matching this signature.
      *
      * -keepclassmembers class ** {
@@ -351,13 +297,6 @@
      * }
      */
     private static final String METHOD_PREFIX = "onBusEvent";
-    private static final String INTERPROCESS_METHOD_PREFIX = "onInterprocessBusEvent";
-
-    // Ensures that interprocess events can only be sent from a process holding this permission. */
-    private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
-
-    // Used for passing event data across process boundaries
-    private static final String EXTRA_INTERPROCESS_EVENT_BUNDLE = "interprocess_event_bundle";
 
     // The default priority of all subscribers
     private static final int DEFAULT_SUBSCRIBER_PRIORITY = 1;
@@ -383,10 +322,6 @@
     // The handler to post all events
     private Handler mHandler;
 
-    // Keep track of whether we have registered a broadcast receiver already, so that we can
-    // unregister ourselves before re-registering again with a new IntentFilter.
-    private boolean mHasRegisteredReceiver;
-
     /**
      * Map from event class -> event handler list.  Keeps track of the actual mapping from event
      * to subscriber method.
@@ -401,13 +336,6 @@
     private HashMap<Class<? extends Object>, ArrayList<EventHandlerMethod>> mSubscriberTypeMap = new HashMap<>();
 
     /**
-     * Map from interprocess event name -> interprocess event class.  Used for mapping the event
-     * name after receiving the broadcast, to the event type.  After which a new instance is created
-     * and posted in the local process.
-     */
-    private HashMap<String, Class<? extends InterprocessEvent>> mInterprocessEventNameMap = new HashMap<>();
-
-    /**
      * Set of all currently registered subscribers
      */
     private ArrayList<Subscriber> mSubscribers = new ArrayList<>();
@@ -447,7 +375,7 @@
      *                   be scanned for appropriate event handler methods.
      */
     public void register(Object subscriber) {
-        registerSubscriber(subscriber, DEFAULT_SUBSCRIBER_PRIORITY, null);
+        registerSubscriber(subscriber, DEFAULT_SUBSCRIBER_PRIORITY);
     }
 
     /**
@@ -460,44 +388,7 @@
      *                 subscribers
      */
     public void register(Object subscriber, int priority) {
-        registerSubscriber(subscriber, priority, null);
-    }
-
-    /**
-     * Explicitly registers a subscriber to receive interprocess events with the default priority.
-     *
-     * @param subscriber the subscriber to handle events.  If this is the first instance of the
-     *                   subscriber's class type that has been registered, the class's methods will
-     *                   be scanned for appropriate event handler methods.
-     */
-    public void registerInterprocessAsCurrentUser(Context context, Object subscriber) {
-        registerInterprocessAsCurrentUser(context, subscriber, DEFAULT_SUBSCRIBER_PRIORITY);
-    }
-
-    /**
-     * Registers a subscriber to receive interprocess events with the given priority.
-     *
-     * @param subscriber the subscriber to handle events.  If this is the first instance of the
-     *                   subscriber's class type that has been registered, the class's methods will
-     *                   be scanned for appropriate event handler methods.
-     * @param priority the priority that this subscriber will receive events relative to other
-     *                 subscribers
-     */
-    public void registerInterprocessAsCurrentUser(Context context, Object subscriber, int priority) {
-        if (DEBUG_TRACE_ALL) {
-            logWithPid("registerInterprocessAsCurrentUser(" + subscriber.getClass().getSimpleName() + ")");
-        }
-
-        // Register the subscriber normally, and update the broadcast receiver filter if this is
-        // a new subscriber type with interprocess events
-        MutableBoolean hasInterprocessEventsChanged = new MutableBoolean(false);
-        registerSubscriber(subscriber, priority, hasInterprocessEventsChanged);
-        if (DEBUG_TRACE_ALL) {
-            logWithPid("hasInterprocessEventsChanged: " + hasInterprocessEventsChanged.value);
-        }
-        if (hasInterprocessEventsChanged.value) {
-            registerReceiverForInterprocessEvents(context);
-        }
+        registerSubscriber(subscriber, priority);
     }
 
     /**
@@ -538,18 +429,6 @@
     }
 
     /**
-     * Explicit unregistration for interprocess event subscribers.  This actually behaves exactly
-     * the same as unregister() since we also do not want to stop listening for specific
-     * inter-process messages in case new instances of that subscriber is registered.
-     */
-    public void unregisterInterprocess(Context context, Object subscriber) {
-        if (DEBUG_TRACE_ALL) {
-            logWithPid("unregisterInterprocess()");
-        }
-        unregister(subscriber);
-    }
-
-    /**
      * Sends an event to the subscribers of the given event type immediately.  This can only be
      * called from the same thread as the EventBus's looper thread (for the default EventBus, this
      * is the main application thread).
@@ -599,57 +478,6 @@
         }
     }
 
-    /** Prevent post()ing an InterprocessEvent */
-    @Deprecated
-    public void post(InterprocessEvent event) {
-        throw new RuntimeException("Not supported, use postInterprocess");
-    }
-
-    /** Prevent send()ing an InterprocessEvent */
-    @Deprecated
-    public void send(InterprocessEvent event) {
-        throw new RuntimeException("Not supported, use postInterprocess");
-    }
-
-    /**
-     * Posts an interprocess event.
-     */
-    public void postInterprocess(Context context, final InterprocessEvent event) {
-        if (DEBUG_TRACE_ALL) {
-            logWithPid("postInterprocess(" + event.getClass().getSimpleName() + ")");
-        }
-        String eventType = event.getClass().getName();
-        Bundle eventBundle = event.toBundle();
-        Intent intent = new Intent(eventType);
-        intent.setPackage(context.getPackageName());
-        intent.putExtra(EXTRA_INTERPROCESS_EVENT_BUNDLE, eventBundle);
-        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
-                Intent.FLAG_RECEIVER_FOREGROUND);
-        context.sendBroadcastAsUser(intent, UserHandle.ALL);
-    }
-
-    /**
-     * Receiver for interprocess events.
-     */
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        if (DEBUG_TRACE_ALL) {
-            logWithPid("onReceive(" + intent.getAction() + ", user " + UserHandle.myUserId() + ")");
-        }
-
-        Bundle eventBundle = intent.getBundleExtra(EXTRA_INTERPROCESS_EVENT_BUNDLE);
-        Class<? extends InterprocessEvent> eventType = mInterprocessEventNameMap.get(intent.getAction());
-        try {
-            Constructor<? extends InterprocessEvent> ctor = eventType.getConstructor(Bundle.class);
-            send((Event) ctor.newInstance(eventBundle));
-        } catch (NoSuchMethodException|
-                InvocationTargetException|
-                InstantiationException|
-                IllegalAccessException e) {
-            Log.e(TAG, "Failed to create InterprocessEvent", e.getCause());
-        }
-    }
-
     /**
      * @return a dump of the current state of the EventBus
      */
@@ -711,8 +539,7 @@
     /**
      * Registers a new subscriber.
      */
-    private void registerSubscriber(Object subscriber, int priority,
-            MutableBoolean hasInterprocessEventsChangedOut) {
+    private void registerSubscriber(Object subscriber, int priority) {
         // Fail immediately if we are being called from the non-main thread
         long callingThreadId = Thread.currentThread().getId();
         if (callingThreadId != mHandler.getLooper().getThread().getId()) {
@@ -759,32 +586,16 @@
         }
 
         // Find all the valid event bus handler methods of the subscriber
-        MutableBoolean isInterprocessEvent = new MutableBoolean(false);
         Method[] methods = subscriberType.getDeclaredMethods();
         for (Method m : methods) {
             Class<?>[] parameterTypes = m.getParameterTypes();
-            isInterprocessEvent.value = false;
-            if (isValidEventBusHandlerMethod(m, parameterTypes, isInterprocessEvent)) {
+            if (isValidEventBusHandlerMethod(m, parameterTypes)) {
                 Class<? extends Event> eventType = (Class<? extends Event>) parameterTypes[0];
                 ArrayList<EventHandler> eventTypeHandlers = mEventTypeMap.get(eventType);
                 if (eventTypeHandlers == null) {
                     eventTypeHandlers = new ArrayList<>();
                     mEventTypeMap.put(eventType, eventTypeHandlers);
                 }
-                if (isInterprocessEvent.value) {
-                    try {
-                        // Enforce that the event must have a Bundle constructor
-                        eventType.getConstructor(Bundle.class);
-
-                        mInterprocessEventNameMap.put(eventType.getName(),
-                                (Class<? extends InterprocessEvent>) eventType);
-                        if (hasInterprocessEventsChangedOut != null) {
-                            hasInterprocessEventsChangedOut.value = true;
-                        }
-                    } catch (NoSuchMethodException e) {
-                        throw new RuntimeException("Expected InterprocessEvent to have a Bundle constructor");
-                    }
-                }
                 EventHandlerMethod method = new EventHandlerMethod(m, eventType);
                 EventHandler handler = new EventHandler(sub, method, priority);
                 eventTypeHandlers.add(handler);
@@ -793,8 +604,7 @@
 
                 if (DEBUG_TRACE_ALL) {
                     logWithPid("  * Method: " + m.getName() +
-                            " event: " + parameterTypes[0].getSimpleName() +
-                            " interprocess? " + isInterprocessEvent.value);
+                            " event: " + parameterTypes[0].getSimpleName());
                 }
             }
         }
@@ -830,12 +640,7 @@
             final EventHandler eventHandler = eventHandlers.get(i);
             if (eventHandler.subscriber.getReference() != null) {
                 if (event.requiresPost) {
-                    mHandler.post(new Runnable() {
-                        @Override
-                        public void run() {
-                            processEvent(eventHandler, event);
-                        }
-                    });
+                    mHandler.post(() -> processEvent(eventHandler, event));
                     hasPostedEvent = true;
                 } else {
                     processEvent(eventHandler, event);
@@ -845,12 +650,7 @@
 
         // Clean up after this event, deferring until all subscribers have been called
         if (hasPostedEvent) {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    event.onPostDispatch();
-                }
-            });
+            mHandler.post(event::onPostDispatch);
         } else {
             event.onPostDispatch();
         }
@@ -898,29 +698,6 @@
     }
 
     /**
-     * Re-registers the broadcast receiver for any new messages that we want to listen for.
-     */
-    private void registerReceiverForInterprocessEvents(Context context) {
-        if (DEBUG_TRACE_ALL) {
-            logWithPid("registerReceiverForInterprocessEvents()");
-        }
-        // Rebuild the receiver filter with the new interprocess events
-        IntentFilter filter = new IntentFilter();
-        for (String eventName : mInterprocessEventNameMap.keySet()) {
-            filter.addAction(eventName);
-            if (DEBUG_TRACE_ALL) {
-                logWithPid("  filter: " + eventName);
-            }
-        }
-        // Re-register the receiver with the new filter
-        if (mHasRegisteredReceiver) {
-            context.unregisterReceiver(this);
-        }
-        context.registerReceiverAsUser(this, UserHandle.ALL, filter, PERMISSION_SELF, mHandler);
-        mHasRegisteredReceiver = true;
-    }
-
-    /**
      * Returns whether this subscriber is currently registered.  If {@param removeFoundSubscriber}
      * is true, then remove the subscriber before returning.
      */
@@ -940,28 +717,19 @@
     /**
      * @return whether {@param method} is a valid (normal or interprocess) event bus handler method
      */
-    private boolean isValidEventBusHandlerMethod(Method method, Class<?>[] parameterTypes,
-            MutableBoolean isInterprocessEventOut) {
+    private boolean isValidEventBusHandlerMethod(Method method, Class<?>[] parameterTypes) {
         int modifiers = method.getModifiers();
         if (Modifier.isPublic(modifiers) &&
                 Modifier.isFinal(modifiers) &&
                 method.getReturnType().equals(Void.TYPE) &&
                 parameterTypes.length == 1) {
-            if (EventBus.InterprocessEvent.class.isAssignableFrom(parameterTypes[0]) &&
-                    method.getName().startsWith(INTERPROCESS_METHOD_PREFIX)) {
-                isInterprocessEventOut.value = true;
-                return true;
-            } else if (EventBus.Event.class.isAssignableFrom(parameterTypes[0]) &&
+            if (EventBus.Event.class.isAssignableFrom(parameterTypes[0]) &&
                             method.getName().startsWith(METHOD_PREFIX)) {
-                isInterprocessEventOut.value = false;
                 return true;
             } else {
                 if (DEBUG_TRACE_ALL) {
                     if (!EventBus.Event.class.isAssignableFrom(parameterTypes[0])) {
                         logWithPid("  Expected method take an Event-based parameter: " + method.getName());
-                    } else if (!method.getName().startsWith(INTERPROCESS_METHOD_PREFIX) &&
-                            !method.getName().startsWith(METHOD_PREFIX)) {
-                        logWithPid("  Expected method start with method prefix: " + method.getName());
                     }
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockedTopTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockedTopTaskEvent.java
index f1bc214..9e3ced3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockedTopTaskEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockedTopTaskEvent.java
@@ -26,11 +26,9 @@
  */
 public class DockedTopTaskEvent extends EventBus.Event {
 
-    public int dragMode;
     public Rect initialRect;
 
-    public DockedTopTaskEvent(int dragMode, Rect initialRect) {
-        this.dragMode = dragMode;
+    public DockedTopTaskEvent(Rect initialRect) {
         this.initialRect = initialRect;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
index 1178725..3ed5f70 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
@@ -460,7 +460,7 @@
 
     private void animateSliderTo(int target) {
         if (!mControlValueInitialized) {
-            // Don't animate the first value since it's default state isn't meaningful to users.
+            // Don't animate the first value since its default state isn't meaningful to users.
             mControl.setValue(target);
             mControlValueInitialized = true;
         }
@@ -470,10 +470,12 @@
         mSliderAnimator = ValueAnimator.ofInt(mControl.getValue(), target);
         mSliderAnimator.addUpdateListener((ValueAnimator animation) -> {
             mExternalChange = true;
-            mControl.setValue((int)animation.getAnimatedValue());
+            mControl.setValue((int) animation.getAnimatedValue());
             mExternalChange = false;
         });
-        mSliderAnimator.setDuration(SLIDER_ANIMATION_DURATION);
+        final long animationDuration = SLIDER_ANIMATION_DURATION * Math.abs(
+                mControl.getValue() - target) / GAMMA_SPACE_MAX;
+        mSliderAnimator.setDuration(animationDuration);
         mSliderAnimator.start();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
index 750002c..64fa8f8 100644
--- a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
@@ -18,11 +18,7 @@
 
 import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
 import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
-import static android.os.UserHandle.USER_CURRENT;
 
-import static com.android.systemui.statusbar.phone.NavigationBarGestureHelper.DRAG_MODE_NONE;
-
-import android.app.ActivityManager;
 import android.content.res.Configuration;
 import android.os.RemoteException;
 import android.util.Log;
@@ -30,17 +26,11 @@
 import android.view.KeyEvent;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
-
 import com.android.internal.policy.DividerSnapAlgorithm;
 import com.android.systemui.SystemUI;
 import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.stackdivider.DividerView;
-import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
-
-import java.util.List;
 
 /**
  * Dispatches shortcut to System UI components
@@ -94,7 +84,7 @@
             if (dockSide == WindowManager.DOCKED_INVALID) {
                 // Split the screen
                 Recents recents = getComponent(Recents.class);
-                recents.splitPrimaryTask(DRAG_MODE_NONE, (shortcutCode == SC_DOCK_LEFT)
+                recents.splitPrimaryTask((shortcutCode == SC_DOCK_LEFT)
                         ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
                         : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT, null, -1);
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index da0a435..ea194a7 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -16,29 +16,28 @@
 
 package com.android.systemui.stackdivider;
 
-import android.content.res.Configuration;
-import android.os.RemoteException;
-import android.view.IDockedStackListener;
-import android.view.LayoutInflater;
-import android.view.View;
-
-import com.android.systemui.R;
-import com.android.systemui.SystemUI;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 
+import android.content.res.Configuration;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.IDockedStackListener;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManagerGlobal;
+import com.android.systemui.R;
+import com.android.systemui.SystemUI;
+import com.android.systemui.recents.Recents;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
 /**
  * Controls the docked stack divider.
  */
-public class Divider extends SystemUI {
+public class Divider extends SystemUI implements DividerView.DividerCallbacks {
+    private static final String TAG = "Divider";
+
     private DividerWindowManager mWindowManager;
     private DividerView mView;
     private final DividerState mDividerState = new DividerState();
@@ -55,10 +54,13 @@
         update(mContext.getResources().getConfiguration());
         putComponent(Divider.class, this);
         mDockDividerVisibilityListener = new DockDividerVisibilityListener();
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        ssp.registerDockedStackListener(mDockDividerVisibilityListener);
+        try {
+            WindowManagerGlobal.getWindowManagerService().registerDockedStackListener(
+                    mDockDividerVisibilityListener);
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to register docked stack listener", e);
+        }
         mForcedResizableController = new ForcedResizableInfoActivityController(mContext);
-        EventBus.getDefault().register(this);
     }
 
     @Override
@@ -82,7 +84,7 @@
     private void addDivider(Configuration configuration) {
         mView = (DividerView)
                 LayoutInflater.from(mContext).inflate(R.layout.docked_stack_divider, null);
-        mView.injectDependencies(mWindowManager, mDividerState);
+        mView.injectDependencies(mWindowManager, mDividerState, this);
         mView.setVisibility(mVisible ? View.VISIBLE : View.INVISIBLE);
         mView.setMinimizedDockStack(mMinimized, mHomeStackResizable);
         final int size = mContext.getResources().getDimensionPixelSize(
@@ -156,18 +158,64 @@
         mWindowManager.setTouchable((mHomeStackResizable || !mMinimized) && !mAdjustedForIme);
     }
 
+    public void onRecentsActivityStarting() {
+        if (mView != null) {
+            mView.onRecentsActivityStarting();
+        }
+    }
+
     /**
-     * Workaround for b/62528361, at the time RecentsDrawnEvent is sent, it may happen before a
+     * Workaround for b/62528361, at the time recents has drawn, it may happen before a
      * configuration change to the Divider, and internally, the event will be posted to the
      * subscriber, or DividerView, which has been removed and prevented from resizing. Instead,
      * register the event handler here and proxy the event to the current DividerView.
      */
-    public final void onBusEvent(RecentsDrawnEvent drawnEvent) {
+    public void onRecentsDrawn() {
         if (mView != null) {
             mView.onRecentsDrawn();
         }
     }
 
+    public void onUndockingTask() {
+        if (mView != null) {
+            mView.onUndockingTask();
+        }
+    }
+
+    public void onDockedFirstAnimationFrame() {
+        if (mView != null) {
+            mView.onDockedFirstAnimationFrame();
+        }
+    }
+
+    public void onDockedTopTask() {
+        if (mView != null) {
+            mView.onDockedTopTask();
+        }
+    }
+
+    public void onAppTransitionFinished() {
+        mForcedResizableController.onAppTransitionFinished();
+    }
+
+    @Override
+    public void onDraggingStart() {
+        mForcedResizableController.onDraggingStart();
+    }
+
+    @Override
+    public void onDraggingEnd() {
+        mForcedResizableController.onDraggingEnd();
+    }
+
+    @Override
+    public void growRecents() {
+        Recents recents = getComponent(Recents.class);
+        if (recents != null) {
+            recents.growRecents();
+        }
+    }
+
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.print("  mVisible="); pw.println(mVisible);
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 98925b9..fa01af6 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -55,7 +55,6 @@
 import android.view.animation.Interpolator;
 import android.view.animation.PathInterpolator;
 import android.widget.FrameLayout;
-
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.policy.DividerSnapAlgorithm;
@@ -64,17 +63,8 @@
 import com.android.internal.view.SurfaceFlingerVsyncChoreographer;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent;
-import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
-import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
-import com.android.systemui.recents.events.activity.UndockingTaskEvent;
-import com.android.systemui.recents.events.ui.RecentsGrowingEvent;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.stackdivider.events.StartedDragingEvent;
-import com.android.systemui.stackdivider.events.StoppedDragingEvent;
+import com.android.systemui.shared.system.WindowManagerWrapper;
 import com.android.systemui.statusbar.FlingAnimationUtils;
-import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
 
 /**
  * Docked stack divider.
@@ -82,6 +72,12 @@
 public class DividerView extends FrameLayout implements OnTouchListener,
         OnComputeInternalInsetsListener {
 
+    public interface DividerCallbacks {
+        void onDraggingStart();
+        void onDraggingEnd();
+        void growRecents();
+    }
+
     static final long TOUCH_ANIMATION_DURATION = 150;
     static final long TOUCH_RELEASE_ANIMATION_DURATION = 200;
 
@@ -149,6 +145,7 @@
     private FlingAnimationUtils mFlingAnimationUtils;
     private DividerSnapAlgorithm mSnapAlgorithm;
     private DividerSnapAlgorithm mMinimizedSnapAlgorithm;
+    private DividerCallbacks mCallback;
     private final Rect mStableInsets = new Rect();
 
     private boolean mGrowRecents;
@@ -162,6 +159,7 @@
     private DividerState mState;
     private final SurfaceFlingerVsyncChoreographer mSfChoreographer;
 
+
     // The view is removed or in the process of been removed from the system.
     private boolean mRemoved;
 
@@ -306,7 +304,6 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        EventBus.getDefault().register(this);
 
         // Save the current target if not minimized once attached to window
         if (mHomeStackResizable && mDockSide != WindowManager.DOCKED_INVALID
@@ -315,14 +312,9 @@
         }
     }
 
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        EventBus.getDefault().unregister(this);
-    }
-
     void onDividerRemoved() {
         mRemoved = true;
+        mCallback = null;
         mHandler.removeMessages(MSG_RESIZE_STACK);
     }
 
@@ -364,13 +356,15 @@
         }
     }
 
-    public void injectDependencies(DividerWindowManager windowManager, DividerState dividerState) {
+    public void injectDependencies(DividerWindowManager windowManager, DividerState dividerState,
+            DividerCallbacks callback) {
         mWindowManager = windowManager;
         mState = dividerState;
+        mCallback = callback;
 
         // Set the previous position ratio before minimized state after attaching this divider
         if (mStableInsets.isEmpty()) {
-            SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets);
+            WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);
         }
 
         if (mState.mRatioPositionBeforeMinimized == 0) {
@@ -419,7 +413,9 @@
             mWindowManager.setSlippery(false);
             liftBackground();
         }
-        EventBus.getDefault().send(new StartedDragingEvent());
+        if (mCallback != null) {
+            mCallback.onDraggingStart();
+        }
         return mDockSide != WindowManager.DOCKED_INVALID;
     }
 
@@ -617,7 +613,9 @@
             mCurrentAnimator = null;
             mEntranceAnimationRunning = false;
             mExitAnimationRunning = false;
-            EventBus.getDefault().send(new StoppedDragingEvent());
+            if (mCallback != null) {
+                mCallback.onDraggingEnd();
+            }
 
             // Record last snap target the divider moved to
             if (mHomeStackResizable && !mIsInMinimizeInteraction) {
@@ -776,7 +774,7 @@
             if (mDisplayRotation != mDefaultDisplay.getRotation()) {
                 // Splitscreen to minimize is about to starts after rotating landscape to seascape,
                 // update insets, display info and snap algorithm targets
-                SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets);
+                WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);
                 repositionSnapTargetBeforeMinimized();
                 updateDisplayInfo();
             } else {
@@ -910,7 +908,7 @@
         requestLayout();
 
         // Update the snap position to the new docked side with correct insets
-        SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets);
+        WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);
         mMinimizedSnapAlgorithm = null;
         initializeSnapAlgorithm();
 
@@ -1271,7 +1269,7 @@
         }
     }
 
-    public final void onBusEvent(RecentsActivityStartingEvent recentsActivityStartingEvent) {
+    void onRecentsActivityStarting() {
         if (mGrowRecents && mDockSide == WindowManager.DOCKED_TOP
                 && getSnapAlgorithm().getMiddleTarget() != getSnapAlgorithm().getLastSplitTarget()
                 && getCurrentPosition() == getSnapAlgorithm().getLastSplitTarget().position) {
@@ -1280,16 +1278,14 @@
         }
     }
 
-    public final void onBusEvent(DockedFirstAnimationFrameEvent event) {
+    void onDockedFirstAnimationFrame() {
         saveSnapTargetBeforeMinimized(mSnapAlgorithm.getMiddleTarget());
     }
 
-    public final void onBusEvent(DockedTopTaskEvent event) {
-        if (event.dragMode == NavigationBarGestureHelper.DRAG_MODE_NONE) {
-            mState.growAfterRecentsDrawn = false;
-            mState.animateAfterRecentsDrawn = true;
-            startDragging(false /* animate */, false /* touching */);
-        }
+    void onDockedTopTask() {
+        mState.growAfterRecentsDrawn = false;
+        mState.animateAfterRecentsDrawn = true;
+        startDragging(false /* animate */, false /* touching */);
         updateDockSide();
         mEntranceAnimationRunning = true;
 
@@ -1297,7 +1293,7 @@
                 mSnapAlgorithm.getMiddleTarget());
     }
 
-    public void onRecentsDrawn() {
+    void onRecentsDrawn() {
         updateDockSide();
         final int position = calculatePositionForInsetBounds();
         if (mState.animateAfterRecentsDrawn) {
@@ -1314,13 +1310,15 @@
         if (mState.growAfterRecentsDrawn) {
             mState.growAfterRecentsDrawn = false;
             updateDockSide();
-            EventBus.getDefault().send(new RecentsGrowingEvent());
+            if (mCallback != null) {
+                mCallback.growRecents();
+            }
             stopDragging(position, getSnapAlgorithm().getMiddleTarget(), 336,
                     Interpolators.FAST_OUT_SLOW_IN);
         }
     }
 
-    public final void onBusEvent(UndockingTaskEvent undockingTaskEvent) {
+    void onUndockingTask() {
         int dockSide = mWindowManagerProxy.getDockSide();
         if (dockSide != WindowManager.DOCKED_INVALID && (mHomeStackResizable
                 || !mDockedStackMinimized)) {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivity.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivity.java
index 4415bd7..02f7505 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivity.java
@@ -52,7 +52,7 @@
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.forced_resizable_activity);
-        TextView tv = (TextView) findViewById(com.android.internal.R.id.message);
+        TextView tv = findViewById(com.android.internal.R.id.message);
         int reason = getIntent().getIntExtra(EXTRA_FORCED_RESIZEABLE_REASON, -1);
         String text;
         switch (reason) {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
index 826fa6c..f66db48 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
@@ -16,8 +16,7 @@
 
 package com.android.systemui.stackdivider;
 
-import static com.android.systemui.stackdivider.ForcedResizableInfoActivity
-        .EXTRA_FORCED_RESIZEABLE_REASON;
+import static com.android.systemui.stackdivider.ForcedResizableInfoActivity.EXTRA_FORCED_RESIZEABLE_REASON;
 
 import android.app.ActivityOptions;
 import android.content.Context;
@@ -26,16 +25,9 @@
 import android.os.UserHandle;
 import android.util.ArraySet;
 import android.widget.Toast;
-
 import com.android.systemui.R;
-import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent;
-import com.android.systemui.recents.events.component.ShowUserToastEvent;
-import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
-import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.stackdivider.events.StartedDragingEvent;
-import com.android.systemui.stackdivider.events.StoppedDragingEvent;
+import com.android.systemui.shared.system.TaskStackChangeListener;
 
 /**
  * Controller that decides when to show the {@link ForcedResizableInfoActivity}.
@@ -49,7 +41,7 @@
     private final Handler mHandler = new Handler();
     private final ArraySet<PendingTaskRecord> mPendingTasks = new ArraySet<>();
     private final ArraySet<String> mPackagesShownInSession = new ArraySet<>();
-    private boolean mDividerDraging;
+    private boolean mDividerDragging;
 
     private final Runnable mTimeoutRunnable = new Runnable() {
         @Override
@@ -75,9 +67,8 @@
 
     public ForcedResizableInfoActivityController(Context context) {
         mContext = context;
-        EventBus.getDefault().register(this);
         ActivityManagerWrapper.getInstance().registerTaskStackListener(
-                new SysUiTaskStackChangeListener() {
+                new TaskStackChangeListener() {
                     @Override
                     public void onActivityForcedResizable(String packageName, int taskId,
                             int reason) {
@@ -102,19 +93,19 @@
         }
     }
 
-    public final void onBusEvent(AppTransitionFinishedEvent event) {
-        if (!mDividerDraging) {
+    public void onAppTransitionFinished() {
+        if (!mDividerDragging) {
             showPending();
         }
     }
 
-    public final void onBusEvent(StartedDragingEvent event) {
-        mDividerDraging = true;
+    void onDraggingStart() {
+        mDividerDragging = true;
         mHandler.removeCallbacks(mTimeoutRunnable);
     }
 
-    public final void onBusEvent(StoppedDragingEvent event) {
-        mDividerDraging = false;
+    void onDraggingEnd() {
+        mDividerDragging = false;
         showPending();
     }
 
@@ -127,13 +118,13 @@
     }
 
     private void activityDismissingDockedStack() {
-        EventBus.getDefault().send(new ShowUserToastEvent(
-                R.string.dock_non_resizeble_failed_to_dock_text, Toast.LENGTH_SHORT));
+        Toast.makeText(mContext, R.string.dock_non_resizeble_failed_to_dock_text,
+                Toast.LENGTH_SHORT).show();
     }
 
     private void activityLaunchOnSecondaryDisplayFailed() {
-        EventBus.getDefault().send(new ShowUserToastEvent(
-                R.string.activity_launch_on_secondary_display_failed_text, Toast.LENGTH_SHORT));
+        Toast.makeText(mContext, R.string.activity_launch_on_secondary_display_failed_text,
+                Toast.LENGTH_SHORT).show();
     }
 
     private void showPending() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
index 4516518..b6e88d6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
@@ -165,7 +165,7 @@
      * Whether or not the given notification is alerting and managed by this manager.
      * @return true if the notification is alerting
      */
-    public boolean contains(@NonNull String key) {
+    public boolean isAlerting(@NonNull String key) {
         return mAlertEntries.containsKey(key);
     }
 
@@ -294,7 +294,7 @@
             removeAutoRemovalCallbacks();
 
             if (!isSticky()) {
-                long finishTime = mPostTime + mAutoDismissNotificationDecay;
+                long finishTime = calculateFinishTime();
                 long removeDelay = Math.max(finishTime - currentTime, mMinimumDisplayTime);
                 mHandler.postDelayed(mRemoveAlertRunnable, removeDelay);
             }
@@ -357,6 +357,14 @@
         protected long calculatePostTime() {
             return mClock.currentTimeMillis();
         }
+
+        /**
+         * Calculate when the notification should auto-dismiss itself.
+         * @return the finish time
+         */
+        protected long calculateFinishTime() {
+            return mPostTime + mAutoDismissNotificationDecay;
+        }
     }
 
     protected final static class Clock {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java
new file mode 100644
index 0000000..2c384d0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.ArraySet;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.notification.NotificationData;
+
+/**
+ * Manager which handles high priority notifications that should "pulse" in when the device is
+ * dozing and/or in AOD.  The pulse uses the notification's ambient view and pops in briefly
+ * before automatically dismissing the alert.
+ */
+public final class AmbientPulseManager extends AlertingNotificationManager {
+
+    protected final ArraySet<OnAmbientChangedListener> mListeners = new ArraySet<>();
+    @VisibleForTesting
+    protected long mExtensionTime;
+
+    public AmbientPulseManager(@NonNull final Context context) {
+        Resources resources = context.getResources();
+        mAutoDismissNotificationDecay = resources.getInteger(R.integer.ambient_notification_decay);
+        mMinimumDisplayTime = resources.getInteger(R.integer.ambient_notification_minimum_time);
+        mExtensionTime = resources.getInteger(R.integer.ambient_notification_extension_time);
+    }
+
+    /**
+     * Adds an OnAmbientChangedListener to observe events.
+     */
+    public void addListener(@NonNull OnAmbientChangedListener listener) {
+        mListeners.add(listener);
+    }
+
+    /**
+     * Removes the OnAmbientChangedListener from the observer list.
+     */
+    public void removeListener(@NonNull OnAmbientChangedListener listener) {
+        mListeners.remove(listener);
+    }
+
+    /**
+     * Extends the lifetime of the currently showing pulsing notification so that the pulse lasts
+     * longer.
+     */
+    public void extendPulse() {
+        AmbientEntry topEntry = getTopEntry();
+        if (topEntry == null) {
+            return;
+        }
+        topEntry.extendPulse();
+    }
+
+    @Override
+    protected void onAlertEntryAdded(AlertEntry alertEntry) {
+        NotificationData.Entry entry = alertEntry.mEntry;
+        entry.row.setAmbientPulsing(true);
+        for (OnAmbientChangedListener listener : mListeners) {
+            listener.onAmbientStateChanged(entry, true);
+        }
+    }
+
+    @Override
+    protected void onAlertEntryRemoved(AlertEntry alertEntry) {
+        NotificationData.Entry entry = alertEntry.mEntry;
+        entry.row.setAmbientPulsing(false);
+        for (OnAmbientChangedListener listener : mListeners) {
+            listener.onAmbientStateChanged(entry, false);
+        }
+    }
+
+    @Override
+    protected AlertEntry createAlertEntry() {
+        return new AmbientEntry();
+    }
+
+    /**
+     * Get the top pulsing entry.  This should be the currently showing one if there are multiple.
+     * @return the currently showing entry
+     */
+    private AmbientEntry getTopEntry() {
+        if (mAlertEntries.isEmpty()) {
+            return null;
+        }
+        AlertEntry topEntry = null;
+        for (AlertEntry entry : mAlertEntries.values()) {
+            if (topEntry == null || entry.compareTo(topEntry) < 0) {
+                topEntry = entry;
+            }
+        }
+        return (AmbientEntry) topEntry;
+    }
+
+    /**
+     * Observer interface for any changes in the ambient entries.
+     */
+    public interface OnAmbientChangedListener {
+        /**
+         * Called when an entry starts or stops pulsing.
+         * @param entry the entry that changed
+         * @param isPulsing true if the entry is now pulsing, false otherwise
+         */
+        void onAmbientStateChanged(NotificationData.Entry entry, boolean isPulsing);
+    }
+
+    private final class AmbientEntry extends AlertEntry {
+        private boolean extended;
+
+        /**
+         * Extend the lifetime of the alertEntry so that it auto-removes later.  Can only be
+         * extended once.
+         */
+        private void extendPulse() {
+            if (!extended) {
+                extended = true;
+                updateEntry(false);
+            }
+        }
+
+        @Override
+        public void reset() {
+            super.reset();
+            extended = false;
+        }
+
+        @Override
+        protected long calculateFinishTime() {
+            return super.calculateFinishTime() + (extended ? mExtensionTime : 0);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index e19c844..5c0b328 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -161,7 +161,7 @@
         default void onRotationProposal(int rotation, boolean isValid) { }
 
         default void showBiometricDialog(Bundle bundle, IBiometricPromptReceiver receiver,
-                int type) { }
+                int type, boolean requireConfirmation) { }
         default void onBiometricAuthenticated() { }
         default void onBiometricHelp(String message) { }
         default void onBiometricError(String error) { }
@@ -514,12 +514,14 @@
     }
 
     @Override
-    public void showBiometricDialog(Bundle bundle, IBiometricPromptReceiver receiver, int type) {
+    public void showBiometricDialog(Bundle bundle, IBiometricPromptReceiver receiver, int type,
+            boolean requireConfirmation) {
         synchronized (mLock) {
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = bundle;
             args.arg2 = receiver;
             args.argi1 = type;
+            args.arg3 = requireConfirmation;
             mHandler.obtainMessage(MSG_BIOMETRIC_SHOW, args)
                     .sendToTarget();
         }
@@ -763,7 +765,8 @@
                         mCallbacks.get(i).showBiometricDialog(
                                 (Bundle) someArgs.arg1,
                                 (IBiometricPromptReceiver) someArgs.arg2,
-                                someArgs.argi1);
+                                someArgs.argi1,
+                                (boolean) someArgs.arg3);
                     }
                     someArgs.recycle();
                     break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index 247e3d3..00e0b95 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -16,6 +16,10 @@
 
 package com.android.systemui.statusbar;
 
+import static android.content.Context.LAYOUT_INFLATER_SERVICE;
+import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AlertDialog;
@@ -30,10 +34,10 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.ResolveInfo;
 import android.content.res.ColorStateList;
-import android.graphics.drawable.Icon;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
 import android.hardware.input.InputManager;
 import android.os.Handler;
 import android.os.Looper;
@@ -51,29 +55,23 @@
 import android.view.View.AccessibilityDelegate;
 import android.view.ViewGroup;
 import android.view.Window;
+import android.view.WindowManager;
 import android.view.WindowManager.KeyboardShortcutsReceiver;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.RelativeLayout;
 import android.widget.TextView;
-
 import com.android.internal.app.AssistUtils;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 
-import static android.content.Context.LAYOUT_INFLATER_SERVICE;
-import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
-
 /**
  * Contains functionality for handling keyboard shortcuts.
  */
@@ -372,19 +370,19 @@
 
     private void showKeyboardShortcuts(int deviceId) {
         retrieveKeyCharacterMap(deviceId);
-        SystemServicesProxy.getInstance(mContext).requestKeyboardShortcuts(mContext,
-                new KeyboardShortcutsReceiver() {
-                    @Override
-                    public void onKeyboardShortcutsReceived(
-                            final List<KeyboardShortcutGroup> result) {
-                        result.add(getSystemShortcuts());
-                        final KeyboardShortcutGroup appShortcuts = getDefaultApplicationShortcuts();
-                        if (appShortcuts != null) {
-                            result.add(appShortcuts);
-                        }
-                        showKeyboardShortcutsDialog(result);
-                    }
-                }, deviceId);
+        WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+        wm.requestAppKeyboardShortcuts(new KeyboardShortcutsReceiver() {
+            @Override
+            public void onKeyboardShortcutsReceived(
+                    final List<KeyboardShortcutGroup> result) {
+                result.add(getSystemShortcuts());
+                final KeyboardShortcutGroup appShortcuts = getDefaultApplicationShortcuts();
+                if (appShortcuts != null) {
+                    result.add(appShortcuts);
+                }
+                showKeyboardShortcutsDialog(result);
+            }
+        }, deviceId);
     }
 
     private void dismissKeyboardShortcuts() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 551e8a9..0c5f391 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -298,27 +298,6 @@
         if (mVisible) {
             // Walk down a precedence-ordered list of what indication
             // should be shown based on user or device state
-            if (mDozing) {
-                mTextView.setTextColor(Color.WHITE);
-                if (!TextUtils.isEmpty(mTransientIndication)) {
-                    // When dozing we ignore any text color and use white instead, because
-                    // colors can be hard to read in low brightness.
-                    mTextView.switchIndication(mTransientIndication);
-                } else if (mPowerPluggedIn) {
-                    String indication = computePowerIndication();
-                    if (animate) {
-                        animateText(mTextView, indication);
-                    } else {
-                        mTextView.switchIndication(indication);
-                    }
-                } else {
-                    String percentage = NumberFormat.getPercentInstance()
-                            .format(mBatteryLevel / 100f);
-                    mTextView.switchIndication(percentage);
-                }
-                return;
-            }
-
             KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
             int userId = KeyguardUpdateMonitor.getCurrentUser();
             String trustGrantedIndication = getTrustGrantedIndication();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index d6886f5..89a842e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -16,6 +16,7 @@
 package com.android.systemui.statusbar;
 
 import android.app.ActivityManager;
+import android.app.KeyguardManager;
 import android.app.Notification;
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
@@ -37,12 +38,15 @@
 
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
+import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
 import com.android.systemui.OverviewProxyService;
+import com.android.systemui.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 
 import java.io.FileDescriptor;
@@ -52,7 +56,7 @@
  * Handles keeping track of the current user, profiles, and various things related to hiding
  * contents, redacting notifications, and the lockscreen.
  */
-public class NotificationLockscreenUserManager implements Dumpable {
+public class NotificationLockscreenUserManager implements Dumpable, StateListener {
     private static final String TAG = "LockscreenUserManager";
     private static final boolean ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT = false;
     public static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
@@ -67,9 +71,13 @@
             Dependency.get(DeviceProvisionedController.class);
     private final UserManager mUserManager;
     private final IStatusBarService mBarService;
+    private final LockPatternUtils mLockPatternUtils;
+    private final KeyguardManager mKeyguardManager;
+    private StatusBarKeyguardViewManager mKeyguardViewManager;
 
     private boolean mShowLockscreenNotifications;
     private boolean mAllowLockscreenRemoteInput;
+    private int mState = StatusBarState.SHADE;
 
     protected final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() {
         @Override
@@ -84,7 +92,9 @@
                 mEntryManager.updateNotifications();
             } else if (Intent.ACTION_DEVICE_LOCKED_CHANGED.equals(action)) {
                 if (userId != mCurrentUserId && isCurrentProfile(userId)) {
+                    updatePublicMode();
                     mPresenter.onWorkChallengeChanged();
+                    mEntryManager.updateNotifications();
                 }
             }
         }
@@ -100,8 +110,9 @@
                 Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
 
                 updateLockscreenNotificationSetting();
-
+                updatePublicMode();
                 mPresenter.onUserSwitched(mCurrentUserId);
+                mEntryManager.getNotificationData().filterAndSort();
             } else if (Intent.ACTION_USER_ADDED.equals(action)) {
                 updateCurrentProfilesCache();
             } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
@@ -150,6 +161,9 @@
         mCurrentUserId = ActivityManager.getCurrentUser();
         mBarService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+        mLockPatternUtils = new LockPatternUtils(mContext);
+        mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+        Dependency.get(StatusBarStateController.class).addListener(this);
     }
 
     public void setUpWithPresenter(NotificationPresenter presenter,
@@ -239,6 +253,43 @@
         }
     }
 
+    public void setKeyguardViewManager(StatusBarKeyguardViewManager sbkvm) {
+        mKeyguardViewManager = sbkvm;
+    }
+
+    @Override
+    public void onStateChanged(int newState) {
+        mState = newState;
+        updatePublicMode();
+    }
+
+    public void updatePublicMode() {
+        //TODO: I think there may be a race condition where mKeyguardViewManager.isShowing() returns
+        // false when it should be true. Therefore, if we are not on the SHADE, don't even bother
+        // asking if the keyguard is showing. We still need to check it though because showing the
+        // camera on the keyguard has a state of SHADE but the keyguard is still showing.
+        boolean showingKeyguard = mState != StatusBarState.SHADE
+                || mKeyguardViewManager.isShowing();
+        boolean devicePublic = showingKeyguard && mKeyguardViewManager.isSecure(getCurrentUserId());
+
+        SparseArray<UserInfo> currentProfiles = getCurrentProfiles();
+        for (int i = currentProfiles.size() - 1; i >= 0; i--) {
+            final int userId = currentProfiles.valueAt(i).id;
+            boolean isProfilePublic = devicePublic;
+            if (!devicePublic && userId != mCurrentUserId) {
+                // We can't rely on KeyguardManager#isDeviceLocked() for unified profile challenge
+                // due to a race condition where this code could be called before
+                // TrustManagerService updates its internal records, resulting in an incorrect
+                // state being cached in mLockscreenPublicMode. (b/35951989)
+                if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
+                        && mKeyguardViewManager.isSecure(userId)) {
+                    isProfilePublic = mKeyguardManager.isDeviceLocked(userId);
+                }
+            }
+            setLockscreenPublicMode(isProfilePublic, userId);
+        }
+    }
+
     /**
      * Returns true if notifications are temporarily disabled for this user for security reasons,
      * regardless of the normal settings for that user.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index f7615e6..d8f7b61 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -121,7 +121,8 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        Dependency.get(StatusBarStateController.class).addListener(mStateListener);
+        Dependency.get(StatusBarStateController.class)
+                .addListener(mStateListener, StatusBarStateController.RANK_SHELF);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index d479838..f69ad43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -321,7 +321,7 @@
                         && !row.isLowPriority()));
             }
 
-            entry.row.setShowAmbient(mPresenter.isDozing());
+            entry.row.setOnAmbient(mPresenter.isDozing());
             int userId = entry.notification.getUserId();
             boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
                     entry.notification) && !entry.row.isRemoved();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
index 7a69f2e..d6719f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
@@ -16,42 +16,70 @@
 
 package com.android.systemui.statusbar;
 
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
 import android.util.ArraySet;
+import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+import java.lang.annotation.Retention;
+import java.util.ArrayList;
+import java.util.Comparator;
 
 /**
  * Tracks and reports on {@link StatusBarState}.
  */
 public class StatusBarStateController {
+    private static final String TAG = "SbStateController";
 
     private static final int MAX_STATE = StatusBarState.FULLSCREEN_USER_SWITCHER;
     private static final int MIN_STATE = StatusBarState.SHADE;
 
-    private final ArraySet<StateListener> mListeners = new ArraySet<>();
+    private static final Comparator <RankedListener> mComparator
+            = (o1, o2) -> Integer.compare(o1.rank, o2.rank);
+
+    private final ArrayList<RankedListener> mListeners = new ArrayList<>();
     private int mState;
     private int mLastState;
     private boolean mLeaveOpenOnKeyguardHide;
 
+    // TODO: b/115739177 (remove this explicit ordering if we can)
+    @Retention(SOURCE)
+    @IntDef({RANK_STATUS_BAR, RANK_STATUS_BAR_WINDOW_CONTROLLER, RANK_STACK_SCROLLER, RANK_SHELF})
+    public @interface SbStateListenerRank {}
+    // This is the set of known dependencies when updating StatusBarState
+    public static final int RANK_STATUS_BAR = 0;
+    public static final int RANK_STATUS_BAR_WINDOW_CONTROLLER = 1;
+    public static final int RANK_STACK_SCROLLER = 2;
+    public static final int RANK_SHELF = 3;
+
     public int getState() {
         return mState;
     }
 
-    public void setState(int state) {
+    public boolean setState(int state) {
         if (state > MAX_STATE || state < MIN_STATE) {
             throw new IllegalArgumentException("Invalid state " + state);
         }
         if (state == mState) {
-            return;
+            return false;
         }
         synchronized (mListeners) {
-            for (StateListener listener : new ArraySet<>(mListeners)) {
-                listener.onStatePreChange(mState, state);
+            for (RankedListener rl : new ArrayList<>(mListeners)) {
+                rl.listener.onStatePreChange(mState, state);
             }
             mLastState = mState;
             mState = state;
-            for (StateListener listener : new ArraySet<>(mListeners)) {
-                listener.onStateChanged(mState);
+            for (RankedListener rl : new ArrayList<>(mListeners)) {
+                rl.listener.onStateChanged(mState);
+            }
+
+            for (RankedListener rl : new ArrayList<>(mListeners)) {
+                rl.listener.onStatePostChange();
             }
         }
+
+        return true;
     }
 
     public boolean goingToFullShade() {
@@ -72,20 +100,67 @@
 
     public void addListener(StateListener listener) {
         synchronized (mListeners) {
-            mListeners.add(listener);
+            addListenerInternalLocked(listener, Integer.MAX_VALUE);
         }
     }
 
+    /**
+     * Add a listener and a rank based on the priority of this message
+     * @param listener the listener
+     * @param rank the order in which you'd like to be called. Ranked listeners will be
+     * notified before unranked, and we will sort ranked listeners from low to high
+     *
+     * @deprecated This method exists only to solve latent inter-dependencies from refactoring
+     * StatusBarState out of StatusBar.java. Any new listeners should be built not to need ranking
+     * (i.e., they are non-dependent on the order of operations of StatusBarState listeners).
+     */
+    public void addListener(StateListener listener, @SbStateListenerRank int rank) {
+        synchronized (mListeners) {
+            addListenerInternalLocked(listener, rank);
+        }
+    }
+
+    @GuardedBy("mListeners")
+    private void addListenerInternalLocked(StateListener listener, int rank) {
+        // Protect against double-subscribe
+        for (RankedListener rl : mListeners) {
+            if (rl.listener.equals(listener)) {
+                return;
+            }
+        }
+
+        RankedListener rl = new RankedListener(listener, rank);
+        mListeners.add(rl);
+        mListeners.sort(mComparator);
+    }
+
     public void removeListener(StateListener listener) {
         synchronized (mListeners) {
-            mListeners.remove(listener);
+            mListeners.removeIf((it) -> it.listener.equals(listener));
         }
     }
 
+    public static String describe(int state) {
+        return StatusBarState.toShortString(state);
+    }
+
     public interface StateListener {
         public default void onStatePreChange(int oldState, int newState) {
         }
 
+        public default void onStatePostChange() {
+        }
+
         public void onStateChanged(int newState);
     }
+
+    private class RankedListener {
+        private final StateListener listener;
+        private final int rank;
+
+        private RankedListener(StateListener l, int r) {
+            listener = l;
+            rank = r;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 304a00f..2450e44 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.car;
 
 import android.app.ActivityTaskManager;
-import android.car.user.CarUserManagerHelper;
 import android.graphics.PixelFormat;
 import android.graphics.drawable.Drawable;
 import android.util.Log;
@@ -36,8 +35,8 @@
 import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.fragments.FragmentHostManager;
 import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.car.hvac.HvacController;
 import com.android.systemui.statusbar.car.hvac.TemperatureView;
@@ -461,16 +460,11 @@
         }
     }
 
-
-    public boolean hasDockedTask() {
-        return Recents.getSystemServices().hasDockedTask();
-    }
-
     /**
-     * An implementation of SysUiTaskStackChangeListener, that listens for changes in the system
+     * An implementation of TaskStackChangeListener, that listens for changes in the system
      * task stack and notifies the navigation bar.
      */
-    private class TaskStackListenerImpl extends SysUiTaskStackChangeListener {
+    private class TaskStackListenerImpl extends TaskStackChangeListener {
         @Override
         public void onTaskStackChanged() {
             try {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
index 67e512c..618a4c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
@@ -22,7 +22,7 @@
 import android.app.AlertDialog;
 import android.app.AlertDialog.Builder;
 import android.app.Dialog;
-import android.car.user.CarUserManagerHelper;
+import android.car.userlib.CarUserManagerHelper;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.pm.UserInfo;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
index 53d38c4..f0e5462 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
@@ -29,18 +29,14 @@
 import android.view.RemoteAnimationAdapter;
 import android.view.RemoteAnimationTarget;
 
-import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.shared.system.SurfaceControlCompat;
 import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier;
 import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier.SurfaceParams;
-import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
-import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
 import com.android.systemui.statusbar.phone.NotificationPanelView;
-import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarWindowView;
 
 /**
@@ -59,28 +55,28 @@
     private final NotificationPanelView mNotificationPanel;
     private final NotificationListContainer mNotificationContainer;
     private final StatusBarWindowView mStatusBarWindow;
-    private final StatusBarStateController mStatusBarStateController;
-    private StatusBar mStatusBar;
+    private Callback mCallback;
     private final Runnable mTimeoutRunnable = () -> {
         setAnimationPending(false);
-        mStatusBar.collapsePanel(true /* animate */);
+        mCallback.onExpandAnimationTimedOut();
     };
     private boolean mAnimationPending;
+    private boolean mAnimationRunning;
+    private boolean mIsLaunchForActivity;
 
     public ActivityLaunchAnimator(StatusBarWindowView statusBarWindow,
-            StatusBar statusBar,
+            Callback callback,
             NotificationPanelView notificationPanel,
             NotificationListContainer container) {
         mNotificationPanel = notificationPanel;
         mNotificationContainer = container;
         mStatusBarWindow = statusBarWindow;
-        mStatusBar = statusBar;
-        mStatusBarStateController = Dependency.get(StatusBarStateController.class);
+        mCallback = callback;
     }
 
     public RemoteAnimationAdapter getLaunchAnimation(
             ExpandableNotificationRow sourceNotification, boolean occluded) {
-        if (mStatusBarStateController.getState() != StatusBarState.SHADE || occluded) {
+        if (!mCallback.areLaunchAnimationsEnabled() || occluded) {
             return null;
         }
         AnimationRunner animationRunner = new AnimationRunner(sourceNotification);
@@ -92,10 +88,21 @@
         return mAnimationPending;
     }
 
-    public void setLaunchResult(int launchResult) {
+    /**
+     * Set the launch result the intent requested
+     *
+     * @param launchResult the launch result
+     * @param wasIntentActivity was this launch for an activity
+     */
+    public void setLaunchResult(int launchResult, boolean wasIntentActivity) {
+        mIsLaunchForActivity = wasIntentActivity;
         setAnimationPending((launchResult == ActivityManager.START_TASK_TO_FRONT
                 || launchResult == ActivityManager.START_SUCCESS)
-                        && mStatusBarStateController.getState() == StatusBarState.SHADE);
+                        && mCallback.areLaunchAnimationsEnabled());
+    }
+
+    public boolean isLaunchForActivity() {
+        return mIsLaunchForActivity;
     }
 
     private void setAnimationPending(boolean pending) {
@@ -108,12 +115,16 @@
         }
     }
 
+    public boolean isAnimationRunning() {
+        return mAnimationRunning;
+    }
+
     class AnimationRunner extends IRemoteAnimationRunner.Stub {
 
         private final ExpandableNotificationRow mSourceNotification;
         private final ExpandAnimationParameters mParams;
         private final Rect mWindowCrop = new Rect();
-        private boolean mInstantCollapsePanel = true;
+        private boolean mIsFullScreenLaunch = true;
         private final SyncRtSurfaceTransactionApplier mSyncRtTransactionApplier;
 
         public AnimationRunner(ExpandableNotificationRow sourceNofitication) {
@@ -136,10 +147,10 @@
                 }
 
                 setExpandAnimationRunning(true);
-                mInstantCollapsePanel = primary.position.y == 0
+                mIsFullScreenLaunch = primary.position.y == 0
                         && primary.sourceContainerBounds.height()
                                 >= mNotificationPanel.getHeight();
-                if (!mInstantCollapsePanel) {
+                if (!mIsFullScreenLaunch) {
                     mNotificationPanel.collapseWithDuration(ANIMATION_DURATION);
                 }
                 ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
@@ -192,9 +203,6 @@
                     @Override
                     public void onAnimationEnd(Animator animation) {
                         setExpandAnimationRunning(false);
-                        if (mInstantCollapsePanel) {
-                            mStatusBar.collapsePanel(false /* animate */);
-                        }
                         invokeCallback(iRemoteAnimationFinishedCallback);
                     }
                 });
@@ -228,7 +236,9 @@
             mSourceNotification.setExpandAnimationRunning(running);
             mStatusBarWindow.setExpandAnimationRunning(running);
             mNotificationContainer.setExpandingNotification(running ? mSourceNotification : null);
+            mAnimationRunning = running;
             if (!running) {
+                mCallback.onExpandAnimationFinished(mIsFullScreenLaunch);
                 applyParamsToNotification(null);
                 applyParamsToNotificationList(null);
             }
@@ -257,7 +267,7 @@
         public void onAnimationCancelled() throws RemoteException {
             mSourceNotification.post(() -> {
                 setAnimationPending(false);
-                mStatusBar.onLaunchAnimationCancelled();
+                mCallback.onLaunchAnimationCancelled();
             });
         }
     };
@@ -319,4 +329,30 @@
             return startTranslationZ;
         }
     }
+
+    public interface Callback {
+
+        /**
+         * Called when the launch animation was cancelled.
+         */
+        void onLaunchAnimationCancelled();
+
+        /**
+         * Called when the launch animation has timed out without starting an actual animation.
+         */
+        void onExpandAnimationTimedOut();
+
+        /**
+         * Called when the expand animation has finished.
+         *
+         * @param launchIsFullScreen True if this launch was fullscreen, such that now the window
+         *                           fills the whole screen
+         */
+        void onExpandAnimationFinished(boolean launchIsFullScreen);
+
+        /**
+         * Are animations currently enabled.
+         */
+        boolean areLaunchAnimationsEnabled();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
index 804e842..d097c8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
@@ -440,6 +440,8 @@
             } else if (isHeadsUp) {
                 // Provide consistent ranking with headsUpManager
                 return mHeadsUpManager.compare(a, b);
+            } else if (a.row.isAmbientPulsing() != b.row.isAmbientPulsing()) {
+                return a.row.isAmbientPulsing() ? -1 : 1;
             } else if (aMedia != bMedia) {
                 // Upsort current media notification.
                 return aMedia ? -1 : 1;
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 ac01fa3..a3e982e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -28,15 +28,19 @@
 import android.content.pm.PackageManager;
 import android.database.ContentObserver;
 import android.os.Build;
+import android.os.Bundle;
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.service.dreams.DreamService;
+import android.service.dreams.IDreamManager;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationStats;
 import android.service.notification.StatusBarNotification;
+import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.EventLog;
@@ -56,8 +60,9 @@
 import com.android.systemui.ForegroundServiceController;
 import com.android.systemui.R;
 import com.android.systemui.UiOffloadThread;
-import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.statusbar.NotificationLifetimeExtender;
+import com.android.systemui.statusbar.AlertingNotificationManager;
+import com.android.systemui.statusbar.AmbientPulseManager;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationMediaManager;
@@ -91,7 +96,7 @@
         ExpandableNotificationRow.ExpansionLogger, NotificationUpdateHandler,
         VisualStabilityManager.Callback {
     private static final String TAG = "NotificationEntryMgr";
-    protected static final boolean DEBUG = false;
+    protected static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     protected static final boolean ENABLE_HEADS_UP = true;
     protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
 
@@ -121,12 +126,13 @@
             Dependency.get(ForegroundServiceController.class);
     protected final NotificationListener mNotificationListener =
             Dependency.get(NotificationListener.class);
+    protected AmbientPulseManager mAmbientPulseManager = Dependency.get(AmbientPulseManager.class);
 
+    protected IDreamManager mDreamManager;
     protected IStatusBarService mBarService;
     protected NotificationPresenter mPresenter;
     protected Callback mCallback;
     protected PowerManager mPowerManager;
-    protected SystemServicesProxy mSystemServicesProxy;
     protected NotificationListenerService.RankingMap mLatestRankingMap;
     protected HeadsUpManager mHeadsUpManager;
     protected NotificationData mNotificationData;
@@ -218,8 +224,9 @@
         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mBarService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+        mDreamManager = IDreamManager.Stub.asInterface(
+                ServiceManager.checkService(DreamService.DREAM_SERVICE));
         mMessagingUtil = new NotificationMessagingUtil(context);
-        mSystemServicesProxy = SystemServicesProxy.getInstance(mContext);
         mGroupManager.setPendingEntries(mPendingNotifications);
     }
 
@@ -264,6 +271,7 @@
         }
 
         mNotificationLifetimeExtenders.add(mHeadsUpManager);
+        mNotificationLifetimeExtenders.add(mAmbientPulseManager);
         mNotificationLifetimeExtenders.add(mGutsManager);
         mNotificationLifetimeExtenders.addAll(mRemoteInputManager.getLifetimeExtenders());
 
@@ -381,7 +389,7 @@
         final int userId = n.getUserId();
         try {
             int dismissalSurface = NotificationStats.DISMISSAL_SHADE;
-            if (isHeadsUp(n.getKey())) {
+            if (mHeadsUpManager.isAlerting(n.getKey())) {
                 dismissalSurface = NotificationStats.DISMISSAL_PEEK;
             } else if (mListContainer.hasPulsingNotifications()) {
                 dismissalSurface = NotificationStats.DISMISSAL_AOD;
@@ -432,12 +440,14 @@
     }
 
     private void addEntry(NotificationData.Entry shadeEntry) {
-        boolean isHeadsUped = shouldPeek(shadeEntry);
-        if (isHeadsUped) {
+        if (shouldHeadsUp(shadeEntry)) {
             mHeadsUpManager.showNotification(shadeEntry);
             // Mark as seen immediately
             setNotificationShown(shadeEntry.notification);
         }
+        if (shouldPulse(shadeEntry)) {
+            mAmbientPulseManager.showNotification(shadeEntry);
+        }
         addNotificationViews(shadeEntry);
         mCallback.onNotificationAdded(shadeEntry);
     }
@@ -465,7 +475,11 @@
     private void removeNotificationInternal(String key,
             @Nullable NotificationListenerService.RankingMap ranking, boolean forceRemove) {
         abortExistingInflation(key);
-        if (mHeadsUpManager.contains(key)) {
+
+        // Attempt to remove notifications from their alert managers (heads up, ambient pulse).
+        // Though the remove itself may fail, it lets the manager know to remove as soon as
+        // possible.
+        if (mHeadsUpManager.isAlerting(key)) {
             // A cancel() in response to a remote input shouldn't be delayed, as it makes the
             // sending look longer than it takes.
             // Also we should not defer the removal if reordering isn't allowed since otherwise
@@ -473,10 +487,11 @@
             boolean ignoreEarliestRemovalTime = mRemoteInputManager.getController().isSpinning(key)
                     && !FORCE_REMOTE_INPUT_HISTORY
                     || !mVisualStabilityManager.isReorderingAllowed();
-
-            // Attempt to remove notification.
             mHeadsUpManager.removeNotification(key, ignoreEarliestRemovalTime);
         }
+        if (mAmbientPulseManager.isAlerting(key)) {
+            mAmbientPulseManager.removeNotification(key, false /* ignoreEarliestRemovalTime */);
+        }
 
         NotificationData.Entry entry = mNotificationData.get(key);
 
@@ -651,13 +666,15 @@
     private void addNotificationInternal(StatusBarNotification notification,
             NotificationListenerService.RankingMap rankingMap) throws InflationException {
         String key = notification.getKey();
-        if (DEBUG) Log.d(TAG, "addNotification key=" + key);
+        if (DEBUG) {
+            Log.d(TAG, "addNotification key=" + key);
+        }
 
         mNotificationData.updateRanking(rankingMap);
         NotificationListenerService.Ranking ranking = new NotificationListenerService.Ranking();
         rankingMap.getRanking(key, ranking);
         NotificationData.Entry shadeEntry = createNotificationViews(notification, ranking);
-        boolean isHeadsUped = shouldPeek(shadeEntry);
+        boolean isHeadsUped = shouldHeadsUp(shadeEntry);
         if (!isHeadsUped && notification.getNotification().fullScreenIntent != null) {
             if (shouldSuppressFullScreenIntent(shadeEntry)) {
                 if (DEBUG) {
@@ -672,7 +689,13 @@
             } else {
                 // Stop screensaver if the notification has a fullscreen intent.
                 // (like an incoming phone call)
-                SystemServicesProxy.getInstance(mContext).awakenDreamsAsync();
+                Dependency.get(UiOffloadThread.class).submit(() -> {
+                    try {
+                        mDreamManager.awaken();
+                    } catch (RemoteException e) {
+                        e.printStackTrace();
+                    }
+                });
 
                 // not immersive & a fullscreen alert should be shown
                 if (DEBUG)
@@ -750,7 +773,6 @@
             extender.setShouldManageLifetime(entry, false /* shouldManage */);
         }
 
-        Notification n = notification.getNotification();
         mNotificationData.updateRanking(ranking);
 
         final StatusBarNotification oldNotification = entry.notification;
@@ -763,10 +785,12 @@
         mForegroundServiceController.updateNotification(notification,
                 mNotificationData.getImportance(key));
 
-        boolean shouldPeek = shouldPeek(entry, notification);
-        boolean alertAgain = alertAgain(entry, n);
-
-        updateHeadsUp(key, entry, shouldPeek, alertAgain);
+        boolean alertAgain = alertAgain(entry, entry.notification.getNotification());
+        if (mPresenter.isDozing()) {
+            updateAlertState(entry, shouldPulse(entry), alertAgain, mAmbientPulseManager);
+        } else {
+            updateAlertState(entry, shouldHeadsUp(entry), alertAgain, mHeadsUpManager);
+        }
         updateNotifications();
 
         if (!notification.isClearable()) {
@@ -851,66 +875,163 @@
         }
     }
 
-    protected boolean shouldPeek(NotificationData.Entry entry) {
-        return shouldPeek(entry, entry.notification);
-    }
+    /**
+     * Whether the notification should peek in from the top and alert the user.
+     *
+     * @param entry the entry to check
+     * @return true if the entry should heads up, false otherwise
+     */
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
+    public boolean shouldHeadsUp(NotificationData.Entry entry) {
+        StatusBarNotification sbn = entry.notification;
 
-    public boolean shouldPeek(NotificationData.Entry entry, StatusBarNotification sbn) {
-        if (!mUseHeadsUp || mPresenter.isDeviceInVrMode()) {
-            if (DEBUG) Log.d(TAG, "No peeking: no huns or vr mode");
-            return false;
-        }
-
-        if (mNotificationData.shouldFilterOut(entry)) {
-            if (DEBUG) Log.d(TAG, "No peeking: filtered notification: " + sbn.getKey());
-            return false;
-        }
-
-        boolean inUse = mPowerManager.isScreenOn() && !mSystemServicesProxy.isDreaming();
-
-        if (!inUse && !mPresenter.isDozing()) {
+        if (mPresenter.isDozing()) {
             if (DEBUG) {
-                Log.d(TAG, "No peeking: not in use: " + sbn.getKey());
+                Log.d(TAG, "No heads up: device is dozing: " + sbn.getKey());
             }
             return false;
         }
 
-        if (!mPresenter.isDozing() && mNotificationData.shouldSuppressPeek(entry)) {
-            if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey());
+        if (!canAlertCommon(entry)) {
+            if (DEBUG) {
+                Log.d(TAG, "No heads up: notification shouldn't alert: " + sbn.getKey());
+            }
             return false;
         }
 
-        // Peeking triggers an ambient display pulse, so disable peek is ambient is active
-        if (mPresenter.isDozing() && mNotificationData.shouldSuppressAmbient(entry)) {
-            if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey());
+        if (!mUseHeadsUp || mPresenter.isDeviceInVrMode()) {
+            if (DEBUG) {
+                Log.d(TAG, "No heads up: no huns or vr mode");
+            }
             return false;
         }
 
-        if (entry.hasJustLaunchedFullScreenIntent()) {
-            if (DEBUG) Log.d(TAG, "No peeking: recent fullscreen: " + sbn.getKey());
+        boolean isDreaming = false;
+        try {
+            isDreaming = mDreamManager.isDreaming();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to query dream manager.", e);
+        }
+        boolean inUse = mPowerManager.isScreenOn() && !isDreaming;
+
+        if (!inUse) {
+            if (DEBUG) {
+                Log.d(TAG, "No heads up: not in use: " + sbn.getKey());
+            }
+            return false;
+        }
+
+        if (mNotificationData.shouldSuppressPeek(entry)) {
+            if (DEBUG) {
+                Log.d(TAG, "No heads up: suppressed by DND: " + sbn.getKey());
+            }
             return false;
         }
 
         if (isSnoozedPackage(sbn)) {
-            if (DEBUG) Log.d(TAG, "No peeking: snoozed package: " + sbn.getKey());
+            if (DEBUG) {
+                Log.d(TAG, "No heads up: snoozed package: " + sbn.getKey());
+            }
             return false;
         }
 
-        // Allow peeking for DEFAULT notifications only if we're on Ambient Display.
-        int importanceLevel = mPresenter.isDozing() ? NotificationManager.IMPORTANCE_DEFAULT
-                : NotificationManager.IMPORTANCE_HIGH;
-        if (mNotificationData.getImportance(sbn.getKey()) < importanceLevel) {
-            if (DEBUG) Log.d(TAG, "No peeking: unimportant notification: " + sbn.getKey());
+        if (entry.hasJustLaunchedFullScreenIntent()) {
+            if (DEBUG) {
+                Log.d(TAG, "No heads up: recent fullscreen: " + sbn.getKey());
+            }
             return false;
         }
 
-        // Don't peek notifications that are suppressed due to group alert behavior
+        if (mNotificationData.getImportance(sbn.getKey()) < NotificationManager.IMPORTANCE_HIGH) {
+            if (DEBUG) {
+                Log.d(TAG, "No heads up: unimportant notification: " + sbn.getKey());
+            }
+            return false;
+        }
+
+        if (!mCallback.canHeadsUp(entry, sbn)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Whether or not the notification should "pulse" on the user's display when the phone is
+     * dozing.  This displays the ambient view of the notification.
+     *
+     * @param entry the entry to check
+     * @return true if the entry should ambient pulse, false otherwise
+     */
+    protected boolean shouldPulse(NotificationData.Entry entry) {
+        StatusBarNotification sbn = entry.notification;
+
+        if (!mPresenter.isDozing()) {
+            if (DEBUG) {
+                Log.d(TAG, "No pulsing: not dozing: " + sbn.getKey());
+            }
+            return false;
+        }
+
+        if (!canAlertCommon(entry)) {
+            if (DEBUG) {
+                Log.d(TAG, "No pulsing: notification shouldn't alert: " + sbn.getKey());
+            }
+            return false;
+        }
+
+        if (mNotificationData.shouldSuppressAmbient(entry)) {
+            if (DEBUG) {
+                Log.d(TAG, "No pulsing: ambient effect suppressed: " + sbn.getKey());
+            }
+            return false;
+        }
+
+        if (mNotificationData.getImportance(sbn.getKey())
+                < NotificationManager.IMPORTANCE_DEFAULT) {
+            if (DEBUG) {
+                Log.d(TAG, "No pulsing: not important enough: " + sbn.getKey());
+            }
+            return false;
+        }
+
+        Bundle extras = sbn.getNotification().extras;
+        CharSequence title = extras.getCharSequence(Notification.EXTRA_TITLE);
+        CharSequence text = extras.getCharSequence(Notification.EXTRA_TEXT);
+        if (TextUtils.isEmpty(title) && TextUtils.isEmpty(text)) {
+            if (DEBUG) {
+                Log.d(TAG, "No pulsing: title and text are empty: " + sbn.getKey());
+            }
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Common checks between heads up alerting and ambient pulse alerting.  See
+     * {@link NotificationEntryManager#shouldHeadsUp(NotificationData.Entry)} and
+     * {@link NotificationEntryManager#shouldPulse(NotificationData.Entry)}.  Notifications that
+     * fail any of these checks should not alert at all.
+     *
+     * @param entry the entry to check
+     * @return true if these checks pass, false if the notification should not alert
+     */
+    protected boolean canAlertCommon(NotificationData.Entry entry) {
+        StatusBarNotification sbn = entry.notification;
+
+        if (mNotificationData.shouldFilterOut(entry)) {
+            if (DEBUG) {
+                Log.d(TAG, "No alerting: filtered notification: " + sbn.getKey());
+            }
+            return false;
+        }
+
+        // Don't alert notifications that are suppressed due to group alert behavior
         if (sbn.isGroup() && sbn.getNotification().suppressAlertingDueToGrouping()) {
-            if (DEBUG) Log.d(TAG, "No peeking: suppressed due to group alert behavior");
-            return false;
-        }
-
-        if (!mCallback.shouldPeek(entry, sbn)) {
+            if (DEBUG) {
+                Log.d(TAG, "No alerting: suppressed due to group alert behavior");
+            }
             return false;
         }
 
@@ -933,26 +1054,31 @@
         return mHeadsUpManager.isSnoozed(sbn.getPackageName());
     }
 
-    protected void updateHeadsUp(String key, NotificationData.Entry entry, boolean shouldPeek,
-            boolean alertAgain) {
-        final boolean wasHeadsUp = isHeadsUp(key);
-        if (wasHeadsUp) {
-            if (!shouldPeek) {
+    /**
+     * Update the entry's alert state and call the appropriate {@link AlertingNotificationManager}
+     * method.
+     * @param entry entry to update
+     * @param shouldAlert whether or not it should be alerting
+     * @param alertAgain whether or not an alert should actually come in as if it were new
+     * @param alertManager the alerting notification manager that manages the alert state
+     */
+    private void updateAlertState(NotificationData.Entry entry, boolean shouldAlert,
+            boolean alertAgain, AlertingNotificationManager alertManager) {
+        final boolean wasAlerting = alertManager.isAlerting(entry.key);
+        if (wasAlerting) {
+            if (!shouldAlert) {
                 // We don't want this to be interrupting anymore, lets remove it
-                mHeadsUpManager.removeNotification(key, false /* ignoreEarliestRemovalTime */);
+                alertManager.removeNotification(entry.key,
+                        false /* ignoreEarliestRemovalTime */);
             } else {
-                mHeadsUpManager.updateNotification(entry.key, alertAgain);
+                alertManager.updateNotification(entry.key, alertAgain);
             }
-        } else if (shouldPeek && alertAgain) {
-            // This notification was updated to be a heads-up, show it!
-            mHeadsUpManager.showNotification(entry);
+        } else if (shouldAlert && alertAgain) {
+            // This notification was updated to be alerting, show it!
+            alertManager.showNotification(entry);
         }
     }
 
-    protected boolean isHeadsUp(String key) {
-        return mHeadsUpManager.contains(key);
-    }
-
     /**
      * Callback for NotificationEntryManager.
      */
@@ -1008,12 +1134,12 @@
         void onPerformRemoveNotification(StatusBarNotification statusBarNotification);
 
         /**
-         * Returns true if NotificationEntryManager should peek this notification.
+         * Returns true if NotificationEntryManager can heads up this notification.
          *
-         * @param entry entry of the notification that might be peeked
-         * @param sbn notification that might be peeked
-         * @return true if the notification should be peeked
+         * @param entry entry of the notification that might be heads upped
+         * @param sbn notification that might be heads upped
+         * @return true if the notification can be heads upped
          */
-        boolean shouldPeek(NotificationData.Entry entry, StatusBarNotification sbn);
+        boolean canHeadsUp(NotificationData.Entry entry, StatusBarNotification sbn);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ShadeViewRefactor.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ShadeViewRefactor.java
index f204c42..5ad2ba9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ShadeViewRefactor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ShadeViewRefactor.java
@@ -14,7 +14,10 @@
  * limitations under the License
  */
 
-package java.lang.annotation;
+package com.android.systemui.statusbar.notification;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 
 @Retention(RetentionPolicy.SOURCE)
 public @interface ShadeViewRefactor {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 216ed68..9b1d334 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -174,6 +174,11 @@
      */
     private boolean mOnKeyguard;
 
+    /**
+     * Whether or not the row is currently on the doze screen.
+     */
+    private boolean mOnAmbient;
+
     private Animator mTranslateAnim;
     private ArrayList<View> mTranslateableViews;
     private NotificationContentView mPublicLayout;
@@ -186,7 +191,18 @@
     private NotificationData.Entry mEntry;
     private StatusBarNotification mStatusBarNotification;
     private String mAppName;
+
+    /**
+     * Whether or not the notification is using the heads up view and should peek from the top.
+     */
     private boolean mIsHeadsUp;
+
+    /**
+     * Whether or not the notification is using the ambient display view and is pulsing.  This
+     * occurs when a high priority notification alerts while the phone is dozing or is on AOD.
+     */
+    private boolean mIsAmbientPulsing;
+
     private boolean mLastChronometerRunning = true;
     private ViewStub mChildrenContainerStub;
     private NotificationGroupManager mGroupManager;
@@ -289,7 +305,6 @@
     private float mContentTransformationAmount;
     private boolean mIconsVisible = true;
     private boolean mAboveShelf;
-    private boolean mShowAmbient;
     private boolean mIsLastChild;
     private Runnable mOnDismissRunnable;
     private boolean mIsLowPriority;
@@ -606,6 +621,14 @@
         }
     }
 
+    public boolean isAmbientPulsing() {
+        return mIsAmbientPulsing;
+    }
+
+    public void setAmbientPulsing(boolean isAmbientPulsing) {
+        mIsAmbientPulsing = isAmbientPulsing;
+    }
+
     public void setGroupManager(NotificationGroupManager groupManager) {
         mGroupManager = groupManager;
         mPrivateLayout.setGroupManager(groupManager);
@@ -1014,7 +1037,7 @@
             removeView(mMenuRow.getMenuView());
         }
         mMenuRow = plugin;
-        if (mMenuRow.useDefaultMenuItems()) {
+        if (mMenuRow.shouldUseDefaultMenuItems()) {
             ArrayList<MenuItem> items = new ArrayList<>();
             items.add(NotificationMenuRow.createInfoItem(mContext));
             items.add(NotificationMenuRow.createSnoozeItem(mContext));
@@ -1764,7 +1787,7 @@
             getEntry().expandedIcon.setScrollX((int) -translationX);
         }
         if (mMenuRow.getMenuView() != null) {
-            mMenuRow.onTranslationUpdate(translationX);
+            mMenuRow.onParentTranslationUpdate(translationX);
         }
     }
 
@@ -1854,7 +1877,7 @@
     public void setDark(boolean dark, boolean fade, long delay) {
         super.setDark(dark, fade, delay);
         mDark = dark;
-        if (!mIsHeadsUp) {
+        if (!mIsAmbientPulsing) {
             // Only fade the showing view of the pulsing notification.
             fade = false;
         }
@@ -2155,7 +2178,7 @@
             return mPrivateLayout.getMinHeight();
         } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
             return getMinHeight();
-        } else if (mIsSummaryWithChildren && (!mOnKeyguard || mShowAmbient)) {
+        } else if (mIsSummaryWithChildren && (!mOnKeyguard || mOnAmbient)) {
             return mChildrenContainer.getIntrinsicHeight();
         } else if (isHeadsUpAllowed() && (mIsHeadsUp || mHeadsupDisappearRunning)) {
             if (isPinned() || mHeadsupDisappearRunning) {
@@ -2173,7 +2196,7 @@
     }
 
     private boolean isHeadsUpAllowed() {
-        return !mOnKeyguard && !mShowAmbient;
+        return !mOnKeyguard && !mOnAmbient;
     }
 
     @Override
@@ -2269,7 +2292,7 @@
             notifyHeightChanged(true  /* needsAnimation */);
         }
         if (mMenuRow.getMenuView() != null) {
-            mMenuRow.onHeightUpdate();
+            mMenuRow.onParentHeightUpdate();
         }
         updateContentShiftHeight();
         if (mLayoutListener != null) {
@@ -2520,7 +2543,7 @@
             mGuts.setActualHeight(height);
         }
         if (mMenuRow.getMenuView() != null) {
-            mMenuRow.onHeightUpdate();
+            mMenuRow.onParentHeightUpdate();
         }
     }
 
@@ -2818,11 +2841,11 @@
                 || mExpandAnimationRunning || mChildIsExpanding);
     }
 
-    public void setShowAmbient(boolean showAmbient) {
-        if (showAmbient != mShowAmbient) {
-            mShowAmbient = showAmbient;
+    public void setOnAmbient(boolean onAmbient) {
+        if (onAmbient != mOnAmbient) {
+            mOnAmbient = onAmbient;
             if (mChildrenContainer != null) {
-                mChildrenContainer.notifyShowAmbientChanged();
+                mChildrenContainer.notifyDozingStateChanged();
             }
             notifyHeightChanged(false /* needsAnimation */);
         }
@@ -2891,8 +2914,8 @@
         return getCurrentBottomRoundness() == 0.0f && getCurrentTopRoundness() == 0.0f;
     }
 
-    public boolean isShowingAmbient() {
-        return mShowAmbient;
+    public boolean isOnAmbient() {
+        return mOnAmbient;
     }
 
     public void setAboveShelf(boolean aboveShelf) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 0110610..4963a0c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -725,7 +725,7 @@
     }
 
     public int getMaxHeight() {
-        if (mContainingNotification.isShowingAmbient()) {
+        if (mContainingNotification.isOnAmbient()) {
             return getShowingAmbientView().getHeight();
         } else if (mExpandedChild != null) {
             return getViewHeight(VISIBLE_TYPE_EXPANDED)
@@ -752,7 +752,7 @@
     }
 
     public int getMinHeight(boolean likeGroupExpanded) {
-        if (mContainingNotification.isShowingAmbient()) {
+        if (mContainingNotification.isOnAmbient()) {
             return getShowingAmbientView().getHeight();
         } else if (likeGroupExpanded || !mIsChildInGroup || isGroupExpanded()) {
             return getViewHeight(VISIBLE_TYPE_CONTRACTED);
@@ -1039,7 +1039,7 @@
      * @return one of the static enum types in this view, calculated form the current state
      */
     public int calculateVisibleType() {
-        if (mContainingNotification.isShowingAmbient()) {
+        if (mContainingNotification.isOnAmbient()) {
             if (mIsChildInGroup && mAmbientSingleLineChild != null) {
                 return VISIBLE_TYPE_AMBIENT_SINGLELINE;
             } else if (mAmbientChild != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index 9e2331f..903c272 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -103,8 +103,15 @@
     };
 
     private OnClickListener mOnStopOrMinimizeNotifications = v -> {
-        mExitReason = NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS;
-        swapContent(false);
+        Runnable saveImportance = () -> {
+            mExitReason = NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS;
+            swapContent(false);
+        };
+        if (mCheckSaveListener != null) {
+            mCheckSaveListener.checkSave(saveImportance, mSbn);
+        } else {
+            saveImportance.run();
+        }
     };
 
     private OnClickListener mOnUndo = v -> {
@@ -304,15 +311,7 @@
 
     private void saveImportance() {
         if (!mIsNonblockable) {
-            // Only go through the lock screen/bouncer if the user hit 'Stop notifications'.
-            // Otherwise, update the importance immediately.
-            if (mCheckSaveListener != null
-                    && NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS.equals(
-                            mExitReason)) {
-                mCheckSaveListener.checkSave(this::updateImportance, mSbn);
-            } else {
-                updateImportance();
-            }
+            updateImportance();
         }
     }
 
@@ -523,6 +522,11 @@
         return getHeight();
     }
 
+    @VisibleForTesting
+    public boolean isAnimating() {
+        return mExpandAnimation != null && mExpandAnimation.isRunning();
+    }
+
     /**
      * Runnable to either update the given channel (with a new importance value) or, if no channel
      * is provided, update notifications enabled state for the package.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
index dec88d4..7e60c4b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
@@ -16,14 +16,13 @@
 
 package com.android.systemui.statusbar.notification.row;
 
-import static com.android.systemui.SwipeHelper.SWIPED_FAR_ENOUGH_SIZE_FRACTION;
-
 import java.util.ArrayList;
 
+import static com.android.systemui.SwipeHelper.SWIPED_FAR_ENOUGH_SIZE_FRACTION;
+
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
-import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
 import com.android.systemui.statusbar.AlphaOptimizedImageView;
 import com.android.systemui.statusbar.notification.row.NotificationGuts.GutsContent;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
@@ -38,25 +37,21 @@
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.os.Looper;
-import android.util.Log;
 import android.service.notification.StatusBarNotification;
 import android.view.LayoutInflater;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 import android.widget.FrameLayout.LayoutParams;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnClickListener,
         ExpandableNotificationRow.LayoutListener {
 
     private static final boolean DEBUG = false;
     private static final String TAG = "swipe";
 
-    private static final int ICON_ALPHA_ANIM_DURATION = 200;
-    private static final long SHOW_MENU_DELAY = 60;
-    private static final long SWIPE_MENU_TIMING = 200;
-
     // Notification must be swiped at least this fraction of a single menu item to show menu
     private static final float SWIPED_FAR_ENOUGH_MENU_FRACTION = 0.25f;
     private static final float SWIPED_FAR_ENOUGH_MENU_UNCLEARABLE_FRACTION = 0.15f;
@@ -65,6 +60,9 @@
     // menu item to snap back to menu (else it will cover the menu or it'll be dismissed)
     private static final float SWIPED_BACK_ENOUGH_TO_COVER_FRACTION = 0.2f;
 
+    private static final int ICON_ALPHA_ANIM_DURATION = 200;
+    private static final long SHOW_MENU_DELAY = 60;
+
     private ExpandableNotificationRow mParent;
 
     private Context mContext;
@@ -89,22 +87,20 @@
     private int[] mIconLocation = new int[2];
     private int[] mParentLocation = new int[2];
 
-    private float mHorizSpaceForIcon = -1;
+    private int mHorizSpaceForIcon = -1;
     private int mVertSpaceForIcons = -1;
     private int mIconPadding = -1;
     private int mSidePadding;
 
     private float mAlpha = 0f;
-    private float mPrevX;
 
     private CheckForDrag mCheckForDrag;
     private Handler mHandler;
 
-    private boolean mMenuSnappedTo;
+    private boolean mMenuSnapped;
     private boolean mMenuSnappedOnLeft;
     private boolean mShouldShowMenu;
 
-    private NotificationSwipeActionHelper mSwipeHelper;
     private boolean mIsUserTouching;
 
     public NotificationMenuRow(Context context) {
@@ -134,9 +130,34 @@
         return mSnoozeItem;
     }
 
-    @Override
-    public void setSwipeActionHelper(NotificationSwipeActionHelper helper) {
-        mSwipeHelper = helper;
+    @VisibleForTesting
+    protected ExpandableNotificationRow getParent() {
+        return mParent;
+    }
+
+    @VisibleForTesting
+    protected boolean isMenuOnLeft() {
+        return mOnLeft;
+    }
+
+    @VisibleForTesting
+    protected boolean isMenuSnappedOnLeft() {
+        return mMenuSnappedOnLeft;
+    }
+
+    @VisibleForTesting
+    protected boolean isMenuSnapped() {
+        return mMenuSnapped;
+    }
+
+    @VisibleForTesting
+    protected boolean isDismissing() {
+        return mDismissing;
+    }
+
+    @VisibleForTesting
+    protected boolean isSnapping() {
+        return mSnapping;
     }
 
     @Override
@@ -155,17 +176,37 @@
         return mAlpha > 0;
     }
 
+    @VisibleForTesting
+    protected boolean isUserTouching() {
+        return mIsUserTouching;
+    }
+
+    @Override
+    public boolean shouldShowMenu() {
+        return mShouldShowMenu;
+    }
+
     @Override
     public View getMenuView() {
         return mMenuContainer;
     }
 
+    @VisibleForTesting
+    protected float getTranslation() {
+        return mTranslation;
+    }
+
     @Override
     public void resetMenu() {
         resetState(true);
     }
 
     @Override
+    public void onTouchEnd() {
+        mIsUserTouching = false;
+    }
+
+    @Override
     public void onNotificationUpdated(StatusBarNotification sbn) {
         if (mMenuContainer == null) {
             // Menu hasn't been created yet, no need to do anything.
@@ -222,9 +263,7 @@
             mIconsPlaced = false;
             setMenuLocation();
             if (!mIsUserTouching) {
-                // If the # of items showing changed we need to update the snap position
-                showMenu(mParent, mOnLeft ? getSpaceForMenu() : -getSpaceForMenu(),
-                        0 /* velocity */);
+                onSnapOpen();
             }
         }
     }
@@ -236,7 +275,7 @@
         mAnimating = false;
         mSnapping = false;
         mDismissing = false;
-        mMenuSnappedTo = false;
+        mMenuSnapped = false;
         setMenuLocation();
         if (mMenuListener != null && notify) {
             mMenuListener.onMenuReset(mParent);
@@ -244,185 +283,102 @@
     }
 
     @Override
-    public boolean onTouchEvent(View view, MotionEvent ev, float velocity) {
-        final int action = ev.getActionMasked();
-        switch (action) {
-            case MotionEvent.ACTION_DOWN:
-                mSnapping = false;
-                if (mFadeAnimator != null) {
-                    mFadeAnimator.cancel();
-                }
-                mHandler.removeCallbacks(mCheckForDrag);
+    public void onTouchMove(float delta) {
+        mSnapping = false;
+
+        if (!isTowardsMenu(delta) && isMenuLocationChange()) {
+            // Don't consider it "snapped" if location has changed.
+            mMenuSnapped = false;
+
+            // Changed directions, make sure we check to fade in icon again.
+            if (!mHandler.hasCallbacks(mCheckForDrag)) {
+                // No check scheduled, set null to schedule a new one.
                 mCheckForDrag = null;
-                mPrevX = ev.getRawX();
-                mIsUserTouching = true;
-                break;
-
-            case MotionEvent.ACTION_MOVE:
-                mSnapping = false;
-                float diffX = ev.getRawX() - mPrevX;
-                mPrevX = ev.getRawX();
-                if (!isTowardsMenu(diffX) && isMenuLocationChange()) {
-                    // Don't consider it "snapped" if location has changed.
-                    mMenuSnappedTo = false;
-
-                    // Changed directions, make sure we check to fade in icon again.
-                    if (!mHandler.hasCallbacks(mCheckForDrag)) {
-                        // No check scheduled, set null to schedule a new one.
-                        mCheckForDrag = null;
-                    } else {
-                        // Check scheduled, reset alpha and update location; check will fade it in
-                        setMenuAlpha(0f);
-                        setMenuLocation();
-                    }
-                }
-                if (mShouldShowMenu
-                        && !NotificationStackScrollLayout.isPinnedHeadsUp(view)
-                        && !mParent.areGutsExposed()
-                        && !mParent.isDark()
-                        && (mCheckForDrag == null || !mHandler.hasCallbacks(mCheckForDrag))) {
-                    // Only show the menu if we're not a heads up view and guts aren't exposed.
-                    mCheckForDrag = new CheckForDrag();
-                    mHandler.postDelayed(mCheckForDrag, SHOW_MENU_DELAY);
-                }
-                break;
-
-            case MotionEvent.ACTION_UP:
-                mIsUserTouching = false;
-                return handleUpEvent(ev, view, velocity);
-            case MotionEvent.ACTION_CANCEL:
-                mIsUserTouching = false;
-                cancelDrag();
-                return false;
-        }
-        return false;
-    }
-
-    private boolean handleUpEvent(MotionEvent ev, View animView, float velocity) {
-        // If the menu should not be shown, then there is no need to check if the a swipe
-        // should result in a snapping to the menu. As a result, just check if the swipe
-        // was enough to dismiss the notification.
-        if (!mShouldShowMenu) {
-            if (mSwipeHelper.isDismissGesture(ev)) {
-                dismiss(animView, velocity);
             } else {
-                snapBack(animView, velocity);
+                // Check scheduled, reset alpha and update location; check will fade it in
+                setMenuAlpha(0f);
+                setMenuLocation();
             }
-            return true;
         }
-
-        final boolean gestureTowardsMenu = isTowardsMenu(velocity);
-        final boolean gestureFastEnough =
-                mSwipeHelper.getMinDismissVelocity() <= Math.abs(velocity);
-        final boolean gestureFarEnough =
-                mSwipeHelper.swipedFarEnough(mTranslation, mParent.getWidth());
-        final double timeForGesture = ev.getEventTime() - ev.getDownTime();
-        final boolean showMenuForSlowOnGoing = !mParent.canViewBeDismissed()
-                && timeForGesture >= SWIPE_MENU_TIMING;
-        final float menuSnapTarget = mOnLeft ? getSpaceForMenu() : -getSpaceForMenu();
-
-        if (DEBUG) {
-            Log.d(TAG, "mTranslation= " + mTranslation
-                    + " mAlpha= " + mAlpha
-                    + " velocity= " + velocity
-                    + " mMenuSnappedTo= " + mMenuSnappedTo
-                    + " mMenuSnappedOnLeft= " + mMenuSnappedOnLeft
-                    + " mOnLeft= " + mOnLeft
-                    + " minDismissVel= " + mSwipeHelper.getMinDismissVelocity()
-                    + " isDismissGesture= " + mSwipeHelper.isDismissGesture(ev)
-                    + " gestureTowardsMenu= " + gestureTowardsMenu
-                    + " gestureFastEnough= " + gestureFastEnough
-                    + " gestureFarEnough= " + gestureFarEnough);
+        if (mShouldShowMenu
+                && !NotificationStackScrollLayout.isPinnedHeadsUp(getParent())
+                && !mParent.areGutsExposed()
+                && !mParent.isDark()
+                && (mCheckForDrag == null || !mHandler.hasCallbacks(mCheckForDrag))) {
+            // Only show the menu if we're not a heads up view and guts aren't exposed.
+            mCheckForDrag = new CheckForDrag();
+            mHandler.postDelayed(mCheckForDrag, SHOW_MENU_DELAY);
         }
-
-        if (mMenuSnappedTo && isMenuVisible() && mMenuSnappedOnLeft == mOnLeft) {
-            // Menu was snapped to previously and we're on the same side, figure out if
-            // we should stick to the menu, snap back into place, or dismiss
-            final float maximumSwipeDistance = mHorizSpaceForIcon
-                    * SWIPED_BACK_ENOUGH_TO_COVER_FRACTION;
-            final float targetLeft = getSpaceForMenu() - maximumSwipeDistance;
-            final float targetRight = mParent.getWidth() * SWIPED_FAR_ENOUGH_SIZE_FRACTION;
-            boolean withinSnapMenuThreshold = mOnLeft
-                    ? mTranslation > targetLeft && mTranslation < targetRight
-                    : mTranslation < -targetLeft && mTranslation > -targetRight;
-            boolean shouldSnapTo = mOnLeft ? mTranslation < targetLeft : mTranslation > -targetLeft;
-            if (DEBUG) {
-                Log.d(TAG, "   withinSnapMenuThreshold= " + withinSnapMenuThreshold
-                        + "   shouldSnapTo= " + shouldSnapTo
-                        + "   targetLeft= " + targetLeft
-                        + "   targetRight= " + targetRight);
-            }
-            if (withinSnapMenuThreshold && !mSwipeHelper.isDismissGesture(ev)) {
-                // Haven't moved enough to unsnap from the menu
-                showMenu(animView, menuSnapTarget, velocity);
-            } else if (mSwipeHelper.isDismissGesture(ev) && !shouldSnapTo) {
-                // Only dismiss if we're not moving towards the menu
-                dismiss(animView, velocity);
-            } else {
-                snapBack(animView, velocity);
-            }
-        } else if (!mSwipeHelper.isFalseGesture(ev)
-                && (swipedEnoughToShowMenu() && (!gestureFastEnough || showMenuForSlowOnGoing))
-                || (gestureTowardsMenu && !mSwipeHelper.isDismissGesture(ev))) {
-            // Menu has not been snapped to previously and this is menu revealing gesture
-            showMenu(animView, menuSnapTarget, velocity);
-        } else if (mSwipeHelper.isDismissGesture(ev) && !gestureTowardsMenu) {
-            dismiss(animView, velocity);
-        } else {
-            snapBack(animView, velocity);
-        }
-        return true;
     }
 
-    private void showMenu(View animView, float targetLeft, float velocity) {
-        mMenuSnappedTo = true;
-        mMenuSnappedOnLeft = mOnLeft;
-        mMenuListener.onMenuShown(animView);
-        mSwipeHelper.snap(animView, targetLeft, velocity);
+    @VisibleForTesting
+    protected void beginDrag() {
+        mSnapping = false;
+        if (mFadeAnimator != null) {
+            mFadeAnimator.cancel();
+        }
+        mHandler.removeCallbacks(mCheckForDrag);
+        mCheckForDrag = null;
+        mIsUserTouching = true;
     }
 
-    private void snapBack(View animView, float velocity) {
+    @Override
+    public void onTouchStart() {
+       beginDrag();
+    }
+
+    @Override
+    public void onSnapOpen() {
+        mMenuSnapped = true;
+        mMenuSnappedOnLeft = isMenuOnLeft();
+        if (mMenuListener != null) {
+            mMenuListener.onMenuShown(getParent());
+        }
+    }
+
+    @Override
+    public void onSnapClosed() {
         cancelDrag();
-        mMenuSnappedTo = false;
+        mMenuSnapped = false;
         mSnapping = true;
-        mSwipeHelper.snap(animView, 0 /* leftTarget */, velocity);
     }
 
-    private void dismiss(View animView, float velocity) {
+    @Override
+    public void onDismiss() {
         cancelDrag();
-        mMenuSnappedTo = false;
+        mMenuSnapped = false;
         mDismissing = true;
-        mSwipeHelper.dismiss(animView, velocity);
     }
 
-    private void cancelDrag() {
+    @VisibleForTesting
+    protected void cancelDrag() {
         if (mFadeAnimator != null) {
             mFadeAnimator.cancel();
         }
         mHandler.removeCallbacks(mCheckForDrag);
     }
 
-    /**
-     * @return whether the notification has been translated enough to show the menu and not enough
-     *         to be dismissed.
-     */
-    private boolean swipedEnoughToShowMenu() {
-        final float multiplier = mParent.canViewBeDismissed()
+    @VisibleForTesting
+    protected float getMinimumSwipeDistance() {
+        final float multiplier = getParent().canViewBeDismissed()
                 ? SWIPED_FAR_ENOUGH_MENU_FRACTION
                 : SWIPED_FAR_ENOUGH_MENU_UNCLEARABLE_FRACTION;
-        final float minimumSwipeDistance = mHorizSpaceForIcon * multiplier;
-        return !mSwipeHelper.swipedFarEnough(0, 0) && isMenuVisible()
-                && (mOnLeft ? mTranslation > minimumSwipeDistance
-                        : mTranslation < -minimumSwipeDistance);
+        return mHorizSpaceForIcon * multiplier;
+    }
+
+    @VisibleForTesting
+    protected float getMaximumSwipeDistance() {
+        return mHorizSpaceForIcon * SWIPED_BACK_ENOUGH_TO_COVER_FRACTION;
     }
 
     /**
      * Returns whether the gesture is towards the menu location or not.
      */
-    private boolean isTowardsMenu(float movement) {
+    @Override
+    public boolean isTowardsMenu(float movement) {
         return isMenuVisible()
-                && ((mOnLeft && movement <= 0)
-                        || (!mOnLeft && movement >= 0));
+                && ((isMenuOnLeft() && movement <= 0)
+                        || (!isMenuOnLeft() && movement >= 0));
     }
 
     @Override
@@ -445,7 +401,7 @@
     }
 
     @Override
-    public void onHeightUpdate() {
+    public void onParentHeightUpdate() {
         if (mParent == null || mMenuItems.size() == 0 || mMenuContainer == null) {
             return;
         }
@@ -460,7 +416,7 @@
     }
 
     @Override
-    public void onTranslationUpdate(float translation) {
+    public void onParentTranslationUpdate(float translation) {
         mTranslation = translation;
         if (mAnimating || !mMenuFadedIn) {
             // Don't adjust when animating, or if the menu hasn't been shown yet.
@@ -492,13 +448,15 @@
         final int x = mIconLocation[0] - mParentLocation[0] + centerX;
         final int y = mIconLocation[1] - mParentLocation[1] + centerY;
         final int index = mMenuContainer.indexOfChild(v);
-        mMenuListener.onMenuClicked(mParent, x, y, mMenuItems.get(index));
+        if (mMenuListener != null) {
+            mMenuListener.onMenuClicked(mParent, x, y, mMenuItems.get(index));
+        }
     }
 
     private boolean isMenuLocationChange() {
         boolean onLeft = mTranslation > mIconPadding;
         boolean onRight = mTranslation < -mIconPadding;
-        if ((mOnLeft && onRight) || (!mOnLeft && onLeft)) {
+        if ((isMenuOnLeft() && onRight) || (!isMenuOnLeft() && onLeft)) {
             return true;
         }
         return false;
@@ -506,7 +464,7 @@
 
     private void setMenuLocation() {
         boolean showOnLeft = mTranslation > 0;
-        if ((mIconsPlaced && showOnLeft == mOnLeft) || mSnapping || mMenuContainer == null
+        if ((mIconsPlaced && showOnLeft == isMenuOnLeft()) || isSnapping() || mMenuContainer == null
                 || !mMenuContainer.isAttachedToWindow()) {
             // Do nothing
             return;
@@ -522,7 +480,8 @@
         mIconsPlaced = true;
     }
 
-    private void setMenuAlpha(float alpha) {
+    @VisibleForTesting
+    protected void setMenuAlpha(float alpha) {
         mAlpha = alpha;
         if (mMenuContainer == null) {
             return;
@@ -542,7 +501,8 @@
     /**
      * Returns the horizontal space in pixels required to display the menu.
      */
-    private float getSpaceForMenu() {
+    @VisibleForTesting
+    protected int getSpaceForMenu() {
         return mHorizSpaceForIcon * mMenuContainer.getChildCount();
     }
 
@@ -646,12 +606,71 @@
             parent.addView(menuView);
             menuView.setOnClickListener(this);
             FrameLayout.LayoutParams lp = (LayoutParams) menuView.getLayoutParams();
-            lp.width = (int) mHorizSpaceForIcon;
-            lp.height = (int) mHorizSpaceForIcon;
+            lp.width = mHorizSpaceForIcon;
+            lp.height = mHorizSpaceForIcon;
             menuView.setLayoutParams(lp);
         }
     }
 
+    @VisibleForTesting
+    /**
+     * Determine the minimum offset below which the menu should snap back closed.
+     */
+    protected float getSnapBackThreshold() {
+        return getSpaceForMenu() - getMaximumSwipeDistance();
+    }
+
+    /**
+     * Determine the maximum offset above which the parent notification should be dismissed.
+     * @return
+     */
+    @VisibleForTesting
+    protected float getDismissThreshold() {
+        return getParent().getWidth() * SWIPED_FAR_ENOUGH_SIZE_FRACTION;
+    }
+
+    @Override
+    public boolean isWithinSnapMenuThreshold() {
+        float translation = getTranslation();
+        float snapBackThreshold = getSnapBackThreshold();
+        float targetRight = getDismissThreshold();
+        return isMenuOnLeft()
+                ? translation > snapBackThreshold && translation < targetRight
+                : translation < -snapBackThreshold && translation > -targetRight;
+    }
+
+    @Override
+    public boolean isSwipedEnoughToShowMenu() {
+        final float minimumSwipeDistance = getMinimumSwipeDistance();
+        final float translation = getTranslation();
+        return isMenuVisible() && (isMenuOnLeft() ?
+                translation > minimumSwipeDistance
+                : translation < -minimumSwipeDistance);
+    }
+
+    @Override
+    public int getMenuSnapTarget() {
+        return isMenuOnLeft() ? getSpaceForMenu() : -getSpaceForMenu();
+    }
+
+    @Override
+    public boolean shouldSnapBack() {
+        float translation = getTranslation();
+        float targetLeft = getSnapBackThreshold();
+        return isMenuOnLeft() ? translation < targetLeft : translation > -targetLeft;
+    }
+
+    @Override
+    public boolean isSnappedAndOnSameSide() {
+        return isMenuSnapped() && isMenuVisible()
+                && isMenuSnappedOnLeft() == isMenuOnLeft();
+    }
+
+    @Override
+    public boolean canBeDismissed() {
+        return getParent().canViewBeDismissed();
+    }
+
     public static class NotificationMenuItem implements MenuItem {
         View mMenuView;
         GutsContent mGutsContent;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index 15eaaac..8969aca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -20,14 +20,15 @@
 import android.content.Context;
 import android.view.View;
 
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.AmbientPulseManager;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
 import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.NotificationShelf;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 import java.util.ArrayList;
 
@@ -44,7 +45,7 @@
     private int mSpeedBumpIndex = -1;
     private boolean mDark;
     private boolean mHideSensitive;
-    private HeadsUpManager mHeadsUpManager;
+    private AmbientPulseManager mAmbientPulseManager = Dependency.get(AmbientPulseManager.class);
     private float mStackTranslation;
     private int mLayoutHeight;
     private int mTopPadding;
@@ -207,10 +208,6 @@
         mSpeedBumpIndex = shelfIndex;
     }
 
-    public void setHeadsUpManager(HeadsUpManager headsUpManager) {
-        mHeadsUpManager = headsUpManager;
-    }
-
     public float getStackTranslation() {
         return mStackTranslation;
     }
@@ -334,10 +331,10 @@
     }
 
     public boolean isPulsing(NotificationData.Entry entry) {
-        if (!mPulsing || mHeadsUpManager == null) {
+        if (!mPulsing || mAmbientPulseManager == null) {
             return false;
         }
-        return mHeadsUpManager.getAllEntries().anyMatch(e -> (e == entry));
+        return mAmbientPulseManager.isAlerting(entry.key);
     }
 
     public boolean isPanelTracking() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index 3d44e3c..da089b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -213,7 +213,7 @@
             // calculated correctly as they are used to calculate how many we can fit on the screen.
             boolean isOverflow = i == overflowIndex;
             child.setSingleLineWidthIndention(isOverflow && mOverflowNumber != null &&
-                    !mContainingNotification.isShowingAmbient()
+                    !mContainingNotification.isOnAmbient()
                     ? mOverflowNumber.getMeasuredWidth() : 0);
             child.measure(widthMeasureSpec, newHeightSpec);
             // layout the divider
@@ -406,7 +406,7 @@
         if (childCount > maxAllowedVisibleChildren) {
             int number = childCount - maxAllowedVisibleChildren;
             mOverflowNumber = mHybridGroupManager.bindOverflowNumber(mOverflowNumber, number);
-            if (mContainingNotification.isShowingAmbient()) {
+            if (mContainingNotification.isOnAmbient()) {
                 ExpandableNotificationRow overflowView = mChildren.get(0);
                 HybridNotificationView ambientSingleLineView = overflowView == null ? null
                         : overflowView.getAmbientSingleLineView();
@@ -522,7 +522,7 @@
         if (mUserLocked) {
             expandFactor = getGroupExpandFraction();
         }
-        boolean childrenExpanded = mChildrenExpanded || mContainingNotification.isShowingAmbient();
+        boolean childrenExpanded = mChildrenExpanded || mContainingNotification.isOnAmbient();
         for (int i = 0; i < childCount; i++) {
             if (visibleChildren >= maxAllowedVisibleChildren) {
                 break;
@@ -641,7 +641,7 @@
                     getMaxAllowedVisibleChildren(true /* likeCollapsed */), childCount) - 1);
             mGroupOverFlowState.copyFrom(resultState.getViewStateForView(overflowView));
 
-            if (mContainingNotification.isShowingAmbient()) {
+            if (mContainingNotification.isOnAmbient()) {
                 mGroupOverFlowState.alpha = 0.0f;
             } else if (!mChildrenExpanded) {
                 HybridNotificationView alignView = overflowView.getSingleLineView();
@@ -710,7 +710,7 @@
 
     @VisibleForTesting
     int getMaxAllowedVisibleChildren(boolean likeCollapsed) {
-        if (mContainingNotification.isShowingAmbient()) {
+        if (mContainingNotification.isOnAmbient()) {
             return NUMBER_OF_CHILDREN_WHEN_AMBIENT;
         }
         if (!likeCollapsed && (mChildrenExpanded || mContainingNotification.isUserLocked())
@@ -900,7 +900,7 @@
         return mCurrentHeader;
     }
 
-    public void notifyShowAmbientChanged() {
+    public void notifyDozingStateChanged() {
         updateHeaderVisibility(false);
         updateGroupOverflow();
     }
@@ -970,7 +970,7 @@
 
     private ViewGroup calculateDesiredHeader() {
         ViewGroup desiredHeader;
-        if (mContainingNotification.isShowingAmbient()) {
+        if (mContainingNotification.isOnAmbient()) {
             desiredHeader = mNotificationHeaderAmbient;
         } else if (showingAsLowPriority()) {
             desiredHeader = mNotificationHeaderLowPriority;
@@ -1126,7 +1126,7 @@
     }
 
     public int getMinHeight() {
-        return getMinHeight(mContainingNotification.isShowingAmbient()
+        return getMinHeight(mContainingNotification.isOnAmbient()
                 ? NUMBER_OF_CHILDREN_WHEN_AMBIENT
                 : NUMBER_OF_CHILDREN_WHEN_COLLAPSED, false /* likeHighPriority */);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 52844fe..9978ec3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -26,7 +26,6 @@
 import android.animation.TimeAnimator;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.annotation.FloatRange;
 import android.annotation.Nullable;
 import android.app.WallpaperManager;
 import android.content.Context;
@@ -88,7 +87,6 @@
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.DragDownHelper.DragDownCallback;
@@ -110,11 +108,14 @@
 import com.android.systemui.statusbar.notification.row.NotificationGuts;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.NotificationShelf;
+import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.row.NotificationSnooze;
 import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
 import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.FakeShadowView;
 import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.notification.ShadeViewRefactor;
+import com.android.systemui.statusbar.notification.ShadeViewRefactor.RefactorComponent;
 import com.android.systemui.statusbar.notification.VisibilityLocationProvider;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
@@ -134,8 +135,6 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.lang.annotation.ShadeViewRefactor;
-import java.lang.annotation.ShadeViewRefactor.RefactorComponent;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -147,11 +146,9 @@
  * A layout which handles a dynamic amount of notifications and presents them in a scrollable stack.
  */
 public class NotificationStackScrollLayout extends ViewGroup
-        implements Callback, ExpandHelper.Callback, ScrollAdapter,
-        OnHeightChangedListener, OnGroupChangeListener,
-        OnMenuEventListener, VisibilityLocationProvider,
-        NotificationListContainer, ConfigurationListener, DragDownCallback, AnimationStateHandler,
-        Dumpable {
+        implements ExpandHelper.Callback, ScrollAdapter, OnHeightChangedListener,
+        OnGroupChangeListener, VisibilityLocationProvider, NotificationListContainer,
+        ConfigurationListener, DragDownCallback, AnimationStateHandler, Dumpable {
 
     public static final float BACKGROUND_ALPHA_DIMMED = 0.7f;
     private static final String TAG = "StackScroller";
@@ -165,7 +162,7 @@
     private static final int INVALID_POINTER = -1;
 
     private ExpandHelper mExpandHelper;
-    private NotificationSwipeHelper mSwipeHelper;
+    private final NotificationSwipeHelper mSwipeHelper;
     private boolean mSwipingInProgress;
     private int mCurrentStackHeight = Integer.MAX_VALUE;
     private final Paint mBackgroundPaint = new Paint();
@@ -292,10 +289,6 @@
      */
     private int mMaxScrollAfterExpand;
     private ExpandableNotificationRow.LongPressListener mLongPressListener;
-
-    private NotificationMenuRowPlugin mCurrMenuRow;
-    private View mTranslatingParentView;
-    private View mMenuExposedView;
     boolean mCheckForLeavebehind;
 
     /**
@@ -467,6 +460,9 @@
     private Interpolator mDarkXInterpolator = Interpolators.FAST_OUT_SLOW_IN;
     private NotificationPanelView mNotificationPanel;
 
+    private final NotificationGutsManager
+            mNotificationGutsManager = Dependency.get(NotificationGutsManager.class);
+
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     public NotificationStackScrollLayout(Context context) {
         this(context, null);
@@ -496,7 +492,8 @@
                 minHeight, maxHeight);
         mExpandHelper.setEventSource(this);
         mExpandHelper.setScrollAdapter(this);
-        mSwipeHelper = new NotificationSwipeHelper(SwipeHelper.X, this, getContext());
+        mSwipeHelper = new NotificationSwipeHelper(SwipeHelper.X, new SwipeHelperCallback(),
+                getContext(), new NotificationMenuListener());
         mStackScrollAlgorithm = createStackScrollAlgorithm(context);
         initView(context);
         mFalsingManager = FalsingManager.getInstance(context);
@@ -620,7 +617,8 @@
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        Dependency.get(StatusBarStateController.class).addListener(mStateListener);
+        Dependency.get(StatusBarStateController.class)
+                .addListener(mStateListener, StatusBarStateController.RANK_STACK_SCROLLER);
         Dependency.get(ConfigurationController.class).addCallback(this);
     }
 
@@ -639,41 +637,6 @@
     }
 
     @Override
-    @ShadeViewRefactor(RefactorComponent.INPUT)
-    public void onMenuClicked(View view, int x, int y, MenuItem item) {
-        if (mLongPressListener == null) {
-            return;
-        }
-        if (view instanceof ExpandableNotificationRow) {
-            ExpandableNotificationRow row = (ExpandableNotificationRow) view;
-            MetricsLogger.action(mContext, MetricsEvent.ACTION_TOUCH_GEAR,
-                    row.getStatusBarNotification().getPackageName());
-        }
-        mLongPressListener.onLongPress(view, x, y, item);
-    }
-
-    @Override
-    @ShadeViewRefactor(RefactorComponent.INPUT)
-    public void onMenuReset(View row) {
-        if (mTranslatingParentView != null && row == mTranslatingParentView) {
-            mMenuExposedView = null;
-            mTranslatingParentView = null;
-        }
-    }
-
-    @Override
-    @ShadeViewRefactor(RefactorComponent.INPUT)
-    public void onMenuShown(View row) {
-        mMenuExposedView = mTranslatingParentView;
-        if (row instanceof ExpandableNotificationRow) {
-            MetricsLogger.action(mContext, MetricsEvent.ACTION_REVEAL_GEAR,
-                    ((ExpandableNotificationRow) row).getStatusBarNotification()
-                            .getPackageName());
-        }
-        mSwipeHelper.onMenuShown(row);
-    }
-
-    @Override
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     public void onUiModeChanged() {
         mBgColor = mContext.getColor(R.color.notification_shade_background_color);
@@ -1295,111 +1258,6 @@
         mQsContainer = qsContainer;
     }
 
-    /**
-     * Handles cleanup after the given {@code view} has been fully swiped out (including
-     * re-invoking dismiss logic in case the notification has not made its way out yet).
-     */
-    @Override
-    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    public void onChildDismissed(View view) {
-        ExpandableNotificationRow row = (ExpandableNotificationRow) view;
-        if (!row.isDismissed()) {
-            handleChildViewDismissed(view);
-        }
-        ViewGroup transientContainer = row.getTransientContainer();
-        if (transientContainer != null) {
-            transientContainer.removeTransientView(view);
-        }
-    }
-
-    /**
-     * Starts up notification dismiss and tells the notification, if any, to remove itself from
-     * layout.
-     *
-     * @param view view (e.g. notification) to dismiss from the layout
-     */
-
-    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    private void handleChildViewDismissed(View view) {
-        if (mDismissAllInProgress) {
-            return;
-        }
-
-        boolean isBlockingHelperShown = false;
-
-        setSwipingInProgress(false);
-        if (mDragAnimPendingChildren.contains(view)) {
-            // We start the swipe and finish it in the same frame; we don't want a drag animation.
-            mDragAnimPendingChildren.remove(view);
-        }
-        mAmbientState.onDragFinished(view);
-        updateContinuousShadowDrawing();
-
-        if (view instanceof ExpandableNotificationRow) {
-            ExpandableNotificationRow row = (ExpandableNotificationRow) view;
-            if (row.isHeadsUp()) {
-                mHeadsUpManager.addSwipedOutNotification(row.getStatusBarNotification().getKey());
-            }
-            isBlockingHelperShown =
-                    row.performDismissWithBlockingHelper(false /* fromAccessibility */);
-        }
-
-        if (!isBlockingHelperShown) {
-            mSwipedOutViews.add(view);
-        }
-        mFalsingManager.onNotificationDismissed();
-        if (mFalsingManager.shouldEnforceBouncer()) {
-            mStatusBar.executeRunnableDismissingKeyguard(
-                    null,
-                    null /* cancelAction */,
-                    false /* dismissShade */,
-                    true /* afterKeyguardGone */,
-                    false /* deferred */);
-        }
-    }
-
-    @Override
-    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    public void onChildSnappedBack(View animView, float targetLeft) {
-        mAmbientState.onDragFinished(animView);
-        updateContinuousShadowDrawing();
-        if (!mDragAnimPendingChildren.contains(animView)) {
-            if (mAnimationsEnabled) {
-                mSnappedBackChildren.add(animView);
-                mNeedsAnimation = true;
-            }
-            requestChildrenUpdate();
-        } else {
-            // We start the swipe and snap back in the same frame, we don't want any animation
-            mDragAnimPendingChildren.remove(animView);
-        }
-        if (mCurrMenuRow != null && targetLeft == 0) {
-            mCurrMenuRow.resetMenu();
-            mCurrMenuRow = null;
-        }
-    }
-
-    @Override
-    @ShadeViewRefactor(RefactorComponent.INPUT)
-    public boolean updateSwipeProgress(View animView, boolean dismissable, float swipeProgress) {
-        // Returning true prevents alpha fading.
-        return !mFadeNotificationsOnDismiss;
-    }
-
-    @Override
-    @ShadeViewRefactor(RefactorComponent.INPUT)
-    public void onBeginDrag(View v) {
-        mFalsingManager.onNotificatonStartDismissing();
-        setSwipingInProgress(true);
-        mAmbientState.onBeginDrag(v);
-        updateContinuousShadowDrawing();
-        if (mAnimationsEnabled && (mIsExpanded || !isPinnedHeadsUp(v))) {
-            mDragAnimPendingChildren.add(v);
-            mNeedsAnimation = true;
-        }
-        requestChildrenUpdate();
-    }
-
     @ShadeViewRefactor(RefactorComponent.ADAPTER)
     public static boolean isPinnedHeadsUp(View v) {
         if (v instanceof ExpandableNotificationRow) {
@@ -1418,41 +1276,6 @@
         return false;
     }
 
-    @Override
-    @ShadeViewRefactor(RefactorComponent.INPUT)
-    public void onDragCancelled(View v) {
-        mFalsingManager.onNotificatonStopDismissing();
-        setSwipingInProgress(false);
-    }
-
-    @Override
-    @ShadeViewRefactor(RefactorComponent.INPUT)
-    public float getFalsingThresholdFactor() {
-        return mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
-    }
-
-    @Override
-    @ShadeViewRefactor(RefactorComponent.INPUT)
-    public View getChildAtPosition(MotionEvent ev) {
-        View child = getChildAtPosition(ev.getX(), ev.getY());
-        if (child instanceof ExpandableNotificationRow) {
-            ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-            ExpandableNotificationRow parent = row.getNotificationParent();
-            if (parent != null && parent.areChildrenExpanded()
-                    && (parent.areGutsExposed()
-                    || mMenuExposedView == parent
-                    || (parent.getNotificationChildren().size() == 1
-                    && parent.isClearable()))) {
-                // In this case the group is expanded and showing the menu for the
-                // group, further interaction should apply to the group, not any
-                // child notifications so we use the parent of the child. We also do the same
-                // if we only have a single child.
-                child = parent;
-            }
-        }
-        return child;
-    }
-
     @ShadeViewRefactor(RefactorComponent.INPUT)
     public ExpandableView getClosestChildAtRawPosition(float touchX, float touchY) {
         getLocationOnScreen(mTempInt2);
@@ -1696,18 +1519,11 @@
         return mScrollingEnabled;
     }
 
-    @Override
     @ShadeViewRefactor(RefactorComponent.ADAPTER)
-    public boolean canChildBeDismissed(View v) {
+    private boolean canChildBeDismissed(View v) {
         return StackScrollAlgorithm.canChildBeDismissed(v);
     }
 
-    @Override
-    @ShadeViewRefactor(RefactorComponent.INPUT)
-    public boolean isAntiFalsingNeeded() {
-        return onKeyguard();
-    }
-
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     private boolean onKeyguard() {
         return mStatusBarState == StatusBarState.KEYGUARD;
@@ -1787,8 +1603,8 @@
         }
 
         // Check if we need to clear any snooze leavebehinds
-        NotificationGuts guts = mStatusBar.getGutsManager().getExposedGuts();
-        if (guts != null && !isTouchInView(ev, guts)
+        NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
+        if (guts != null && !NotificationSwipeHelper.isTouchInView(ev, guts)
                 && guts.getGutsContent() instanceof NotificationSnooze) {
             NotificationSnooze ns = (NotificationSnooze) guts.getGutsContent();
             if ((ns.isExpanded() && isCancelOrUp)
@@ -3013,11 +2829,11 @@
         }
         // Check if we need to clear any snooze leavebehinds
         boolean isUp = ev.getActionMasked() == MotionEvent.ACTION_UP;
-        NotificationGuts guts = mStatusBar.getGutsManager().getExposedGuts();
-        if (!isTouchInView(ev, guts) && isUp && !swipeWantsIt && !expandWantsIt
-                && !scrollWantsIt) {
+        NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
+        if (!NotificationSwipeHelper.isTouchInView(ev, guts) && isUp && !swipeWantsIt &&
+                !expandWantsIt && !scrollWantsIt) {
             mCheckForLeavebehind = false;
-            mStatusBar.getGutsManager().closeAndSaveGuts(true /* removeLeavebehind */,
+            mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
                     false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
                     false /* resetMenu */);
         }
@@ -3077,8 +2893,8 @@
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
     @Override
     public void cleanUpViewState(View child) {
-        if (child == mTranslatingParentView) {
-            mTranslatingParentView = null;
+        if (child == mSwipeHelper.getTranslatingParentView()) {
+            mSwipeHelper.clearTranslatingParentView();
         }
         mCurrentStackScrollState.removeViewStateForView(child);
     }
@@ -3986,7 +3802,7 @@
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     public void checkSnoozeLeavebehind() {
         if (mCheckForLeavebehind) {
-            mStatusBar.getGutsManager().closeAndSaveGuts(true /* removeLeavebehind */,
+            mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
                     false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
                     false /* resetMenu */);
             mCheckForLeavebehind = false;
@@ -4068,7 +3884,7 @@
     }
 
     @ShadeViewRefactor(RefactorComponent.COORDINATOR)
-    private void setIsExpanded(boolean isExpanded) {
+    public void setIsExpanded(boolean isExpanded) {
         boolean changed = isExpanded != mIsExpanded;
         mIsExpanded = isExpanded;
         mStackScrollAlgorithm.setIsExpanded(isExpanded);
@@ -4248,8 +4064,9 @@
         mDimAnimator.addUpdateListener(mDimUpdateListener);
         mDimAnimator.start();
     }
+
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    public void setHideSensitive(boolean hideSensitive, boolean animate) {
+    private void setHideSensitive(boolean hideSensitive, boolean animate) {
         if (hideSensitive != mAmbientState.isHideSensitive()) {
             int childCount = getChildCount();
             for (int i = 0; i < childCount; i++) {
@@ -4826,7 +4643,6 @@
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     public void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) {
         mHeadsUpManager = headsUpManager;
-        mAmbientState.setHeadsUpManager(headsUpManager);
         mHeadsUpManager.addListener(mRoundnessManager);
         mHeadsUpManager.setAnimationStateHandler(this);
     }
@@ -5008,8 +4824,12 @@
     private void setStatusBarState(int statusBarState) {
         mStatusBarState = statusBarState;
         mAmbientState.setStatusBarState(statusBarState);
+    }
+
+    private void onStatePostChange() {
         boolean onKeyguard = onKeyguard();
         boolean publicMode = mLockscreenUserManager.isAnyProfilePublicMode();
+
         if (mHeadsUpAppearanceController != null) {
             mHeadsUpAppearanceController.setPublicMode(publicMode);
         }
@@ -5026,6 +4846,8 @@
         updateFooter();
         updateChildren();
         onUpdateRowStates();
+
+        mEntryManager.updateNotifications();
     }
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@@ -5236,8 +5058,8 @@
         setFooterView(footerView);
     }
 
-  @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-  private void inflateEmptyShadeView() {
+    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+    private void inflateEmptyShadeView() {
         EmptyShadeView view = (EmptyShadeView) LayoutInflater.from(mContext).inflate(
                 R.layout.status_bar_no_notifications, this, false);
         view.setText(R.string.empty_shade_text);
@@ -5268,8 +5090,8 @@
         mScrimController.setNotificationCount(getNotGoneChildCount());
     }
 
-  @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-  public void setNotificationPanel(NotificationPanelView notificationPanelView) {
+    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+    public void setNotificationPanel(NotificationPanelView notificationPanelView) {
         mNotificationPanel = notificationPanelView;
     }
 
@@ -5287,226 +5109,29 @@
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     public interface OnOverscrollTopChangedListener {
 
-        /**
-         * Notifies a listener that the overscroll has changed.
-         *
-         * @param amount         the amount of overscroll, in pixels
-         * @param isRubberbanded if true, this is a rubberbanded overscroll; if false, this is an
-         *                       unrubberbanded motion to directly expand overscroll view (e.g
-         *                       expand
-         *                       QS)
-         */
-        void onOverscrollTopChanged(float amount, boolean isRubberbanded);
+    /**
+     * Notifies a listener that the overscroll has changed.
+     *
+     * @param amount         the amount of overscroll, in pixels
+     * @param isRubberbanded if true, this is a rubberbanded overscroll; if false, this is an
+     *                       unrubberbanded motion to directly expand overscroll view (e.g
+     *                       expand
+     *                       QS)
+     */
+    void onOverscrollTopChanged(float amount, boolean isRubberbanded);
 
-        /**
-         * Notify a listener that the scroller wants to escape from the scrolling motion and
-         * start a fling animation to the expanded or collapsed overscroll view (e.g expand the QS)
-         *
-         * @param velocity The velocity that the Scroller had when over flinging
-         * @param open     Should the fling open or close the overscroll view.
-         */
-        void flingTopOverscroll(float velocity, boolean open);
-    }
+    /**
+     * Notify a listener that the scroller wants to escape from the scrolling motion and
+     * start a fling animation to the expanded or collapsed overscroll view (e.g expand the QS)
+     *
+     * @param velocity The velocity that the Scroller had when over flinging
+     * @param open     Should the fling open or close the overscroll view.
+     */
+    void flingTopOverscroll(float velocity, boolean open);
+  }
 
-  @ShadeViewRefactor(RefactorComponent.INPUT)
-  private class NotificationSwipeHelper extends SwipeHelper
-            implements NotificationSwipeActionHelper {
-        private static final long COVER_MENU_DELAY = 4000;
-        private Runnable mFalsingCheck;
-        private Handler mHandler;
-
-        public NotificationSwipeHelper(int swipeDirection, Callback callback, Context context) {
-            super(swipeDirection, callback, context);
-            mHandler = new Handler();
-            mFalsingCheck = new Runnable() {
-                @Override
-                public void run() {
-                    resetExposedMenuView(true /* animate */, true /* force */);
-                }
-            };
-        }
-
-        @Override
-        public void onDownUpdate(View currView, MotionEvent ev) {
-            mTranslatingParentView = currView;
-            if (mCurrMenuRow != null) {
-                mCurrMenuRow.onTouchEvent(currView, ev, 0 /* velocity */);
-            }
-            mCurrMenuRow = null;
-            mHandler.removeCallbacks(mFalsingCheck);
-
-            // Slide back any notifications that might be showing a menu
-            resetExposedMenuView(true /* animate */, false /* force */);
-
-            if (currView instanceof ExpandableNotificationRow) {
-                ExpandableNotificationRow row = (ExpandableNotificationRow) currView;
-
-                if (row.getEntry().hasFinishedInitialization()) {
-                    mCurrMenuRow = row.createMenu();
-                    mCurrMenuRow.setSwipeActionHelper(NotificationSwipeHelper.this);
-                    mCurrMenuRow.setMenuClickListener(NotificationStackScrollLayout.this);
-                    mCurrMenuRow.onTouchEvent(currView, ev, 0 /* velocity */);
-                }
-            }
-        }
-
-        @Override
-        public void onMoveUpdate(View view, MotionEvent ev, float translation, float delta) {
-            mHandler.removeCallbacks(mFalsingCheck);
-            if (mCurrMenuRow != null) {
-                mCurrMenuRow.onTouchEvent(view, ev, 0 /* velocity */);
-            }
-        }
-
-        @Override
-        public boolean handleUpEvent(MotionEvent ev, View animView, float velocity,
-                float translation) {
-            if (mCurrMenuRow != null) {
-                return mCurrMenuRow.onTouchEvent(animView, ev, velocity);
-            }
-            return false;
-        }
-
-        @Override
-        public void dismissChild(final View view, float velocity,
-                boolean useAccelerateInterpolator) {
-            super.dismissChild(view, velocity, useAccelerateInterpolator);
-            if (mIsExpanded) {
-                // We don't want to quick-dismiss when it's a heads up as this might lead to closing
-                // of the panel early.
-                handleChildViewDismissed(view);
-            }
-            mStatusBar.getGutsManager().closeAndSaveGuts(true /* removeLeavebehind */,
-                    false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
-                    false /* resetMenu */);
-            handleMenuCoveredOrDismissed();
-        }
-
-        @Override
-        public void snapChild(final View animView, final float targetLeft, float velocity) {
-            super.snapChild(animView, targetLeft, velocity);
-            onDragCancelled(animView);
-            if (targetLeft == 0) {
-                handleMenuCoveredOrDismissed();
-            }
-        }
-
-        @Override
-        public void snooze(StatusBarNotification sbn, SnoozeOption snoozeOption) {
-            mStatusBar.setNotificationSnoozed(sbn, snoozeOption);
-        }
-
-        public boolean isFalseGesture(MotionEvent ev) {
-            return super.isFalseGesture(ev);
-        }
-
-        private void handleMenuCoveredOrDismissed() {
-            if (mMenuExposedView != null && mMenuExposedView == mTranslatingParentView) {
-                mMenuExposedView = null;
-            }
-        }
-
-        @Override
-        public Animator getViewTranslationAnimator(View v, float target,
-                AnimatorUpdateListener listener) {
-            if (v instanceof ExpandableNotificationRow) {
-                return ((ExpandableNotificationRow) v).getTranslateViewAnimator(target, listener);
-            } else {
-                return super.getViewTranslationAnimator(v, target, listener);
-            }
-        }
-
-        @Override
-        public void setTranslation(View v, float translate) {
-            ((ExpandableView) v).setTranslation(translate);
-        }
-
-        @Override
-        public float getTranslation(View v) {
-            return ((ExpandableView) v).getTranslation();
-        }
-
-        @Override
-        public void dismiss(View animView, float velocity) {
-            dismissChild(animView, velocity,
-                    !swipedFastEnough(0, 0) /* useAccelerateInterpolator */);
-        }
-
-        @Override
-        public void snap(View animView, float targetLeft, float velocity) {
-            snapChild(animView, targetLeft, velocity);
-        }
-
-        @Override
-        public boolean swipedFarEnough(float translation, float viewSize) {
-            return swipedFarEnough();
-        }
-
-        @Override
-        public boolean swipedFastEnough(float translation, float velocity) {
-            return swipedFastEnough();
-        }
-
-        @Override
-        public float getMinDismissVelocity() {
-            return getEscapeVelocity();
-        }
-
-        public void onMenuShown(View animView) {
-            onDragCancelled(animView);
-
-            // If we're on the lockscreen we want to false this.
-            if (isAntiFalsingNeeded()) {
-                mHandler.removeCallbacks(mFalsingCheck);
-                mHandler.postDelayed(mFalsingCheck, COVER_MENU_DELAY);
-            }
-        }
-
-        public void closeControlsIfOutsideTouch(MotionEvent ev) {
-            NotificationGuts guts = mStatusBar.getGutsManager().getExposedGuts();
-            View view = null;
-            if (guts != null && !guts.getGutsContent().isLeavebehind()) {
-                // Only close visible guts if they're not a leavebehind.
-                view = guts;
-            } else if (mCurrMenuRow != null && mCurrMenuRow.isMenuVisible()
-                    && mTranslatingParentView != null) {
-                // Checking menu
-                view = mTranslatingParentView;
-            }
-            if (view != null && !isTouchInView(ev, view)) {
-                // Touch was outside visible guts / menu notification, close what's visible
-                mStatusBar.getGutsManager().closeAndSaveGuts(false /* removeLeavebehind */,
-                        false /* force */, true /* removeControls */, -1 /* x */, -1 /* y */,
-                        false /* resetMenu */);
-                resetExposedMenuView(true /* animate */, true /* force */);
-            }
-        }
-
-        public void resetExposedMenuView(boolean animate, boolean force) {
-            if (mMenuExposedView == null
-                    || (!force && mMenuExposedView == mTranslatingParentView)) {
-                // If no menu is showing or it's showing for this view we do nothing.
-                return;
-            }
-            final View prevMenuExposedView = mMenuExposedView;
-            if (animate) {
-                Animator anim = getViewTranslationAnimator(prevMenuExposedView,
-                        0 /* leftTarget */, null /* updateListener */);
-                if (anim != null) {
-                    anim.start();
-                }
-            } else if (mMenuExposedView instanceof ExpandableNotificationRow) {
-                ExpandableNotificationRow row = (ExpandableNotificationRow) mMenuExposedView;
-                if (!row.isRemoved()) {
-                    row.resetTranslation();
-                }
-            }
-            mMenuExposedView = null;
-        }
-    }
-
-  @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-  public boolean hasActiveNotifications() {
+    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+    public boolean hasActiveNotifications() {
         return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty();
     }
 
@@ -5570,8 +5195,8 @@
         return mStatusBarState == StatusBarState.KEYGUARD;
     }
 
-  @ShadeViewRefactor(RefactorComponent.INPUT)
-  public void updateSpeedBumpIndex() {
+    @ShadeViewRefactor(RefactorComponent.INPUT)
+    public void updateSpeedBumpIndex() {
         int speedBumpIndex = 0;
         int currentIndex = 0;
         final int N = getChildCount();
@@ -5591,24 +5216,6 @@
         updateSpeedBumpIndex(speedBumpIndex, noAmbient);
     }
 
-    @ShadeViewRefactor(RefactorComponent.INPUT)
-    private boolean isTouchInView(MotionEvent ev, View view) {
-        if (view == null) {
-            return false;
-        }
-        final int height = (view instanceof ExpandableView)
-                ? ((ExpandableView) view).getActualHeight()
-                : view.getHeight();
-        final int rx = (int) ev.getRawX();
-        final int ry = (int) ev.getRawY();
-        view.getLocationOnScreen(mTempInt2);
-        final int x = mTempInt2[0];
-        final int y = mTempInt2[1];
-        Rect rect = new Rect(x, y, x + view.getWidth(), y + height);
-        boolean ret = rect.contains(rx, ry);
-        return ret;
-    }
-
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
     private void updateContinuousShadowDrawing() {
         boolean continuousShadowUpdate = mAnimationRunning
@@ -5632,11 +5239,29 @@
 
     @ShadeViewRefactor(RefactorComponent.INPUT)
     public void closeControlsIfOutsideTouch(MotionEvent ev) {
-        mSwipeHelper.closeControlsIfOutsideTouch(ev);
+        NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
+        NotificationMenuRowPlugin menuRow = mSwipeHelper.getCurrentMenuRow();
+        View translatingParentView = mSwipeHelper.getTranslatingParentView();
+        View view = null;
+        if (guts != null && !guts.getGutsContent().isLeavebehind()) {
+            // Only close visible guts if they're not a leavebehind.
+            view = guts;
+        } else if (menuRow != null && menuRow.isMenuVisible()
+                && translatingParentView != null) {
+            // Checking menu
+            view = translatingParentView;
+        }
+        if (view != null && !NotificationSwipeHelper.isTouchInView(ev, view)) {
+            // Touch was outside visible guts / menu notification, close what's visible
+            mNotificationGutsManager.closeAndSaveGuts(false /* removeLeavebehind */,
+                    false /* force */, true /* removeControls */, -1 /* x */, -1 /* y */,
+                    false /* resetMenu */);
+            resetExposedMenuView(true /* animate */, true /* force */);
+        }
     }
 
-  @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
-  static class AnimationEvent {
+    @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
+    static class AnimationEvent {
 
         static AnimationFilter[] FILTERS = new AnimationFilter[]{
 
@@ -5936,8 +5561,8 @@
         }
     }
 
-  @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
-  private final StateListener mStateListener = new StateListener() {
+    @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
+    private final StateListener mStateListener = new StateListener() {
         @Override
         public void onStatePreChange(int oldState, int newState) {
             if (oldState == StatusBarState.SHADE_LOCKED && newState == StatusBarState.KEYGUARD) {
@@ -5949,5 +5574,223 @@
         public void onStateChanged(int newState) {
             setStatusBarState(newState);
         }
+
+        @Override
+        public void onStatePostChange() {
+          NotificationStackScrollLayout.this.onStatePostChange();
+      }
     };
+
+    class NotificationMenuListener implements NotificationMenuRowPlugin.OnMenuEventListener {
+        @Override
+        @ShadeViewRefactor(RefactorComponent.INPUT)
+        public void onMenuClicked(View view, int x, int y, MenuItem item) {
+            if (mLongPressListener == null) {
+                return;
+            }
+            if (view instanceof ExpandableNotificationRow) {
+                ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+                MetricsLogger.action(mContext, MetricsEvent.ACTION_TOUCH_GEAR,
+                        row.getStatusBarNotification().getPackageName());
+            }
+            mLongPressListener.onLongPress(view, x, y, item);
+        }
+
+        @Override
+        @ShadeViewRefactor(RefactorComponent.INPUT)
+        public void onMenuReset(View row) {
+            View translatingParentView = mSwipeHelper.getTranslatingParentView();
+            if (translatingParentView != null && row == translatingParentView) {
+                mSwipeHelper.clearExposedMenuView();
+                mSwipeHelper.clearTranslatingParentView();
+            }
+        }
+
+        @Override
+        @ShadeViewRefactor(RefactorComponent.INPUT)
+        public void onMenuShown(View row) {
+            if (row instanceof ExpandableNotificationRow) {
+                MetricsLogger.action(mContext, MetricsEvent.ACTION_REVEAL_GEAR,
+                        ((ExpandableNotificationRow) row).getStatusBarNotification()
+                                .getPackageName());
+            }
+            mSwipeHelper.onMenuShown(row);
+        }
+    }
+
+    class SwipeHelperCallback implements NotificationSwipeHelper.NotificationCallback {
+        @Override
+        public void onDismiss() {
+            mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
+                    false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
+                    false /* resetMenu */);
+        }
+
+        @Override
+        public void onSnooze(StatusBarNotification sbn,
+                NotificationSwipeActionHelper.SnoozeOption snoozeOption) {
+            mStatusBar.setNotificationSnoozed(sbn, snoozeOption);
+        }
+
+        @Override
+        public boolean isExpanded() {
+            return NotificationStackScrollLayout.this.isExpanded();
+        }
+
+        @Override
+        @ShadeViewRefactor(RefactorComponent.INPUT)
+        public void onDragCancelled(View v) {
+            mFalsingManager.onNotificatonStopDismissing();
+            setSwipingInProgress(false);
+        }
+
+        /**
+         * Handles cleanup after the given {@code view} has been fully swiped out (including
+         * re-invoking dismiss logic in case the notification has not made its way out yet).
+         */
+        @Override
+        @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+        public void onChildDismissed(View view) {
+            ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+            if (!row.isDismissed()) {
+                handleChildViewDismissed(view);
+            }
+            ViewGroup transientContainer = row.getTransientContainer();
+            if (transientContainer != null) {
+                transientContainer.removeTransientView(view);
+            }
+        }
+
+        /**
+         * Starts up notification dismiss and tells the notification, if any, to remove itself from
+         * layout.
+         *
+         * @param view view (e.g. notification) to dismiss from the layout
+         */
+
+        @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+        public void handleChildViewDismissed(View view) {
+            if (mDismissAllInProgress) {
+                return;
+            }
+
+            boolean isBlockingHelperShown = false;
+
+            setSwipingInProgress(false);
+            if (mDragAnimPendingChildren.contains(view)) {
+                // We start the swipe and finish it in the same frame; we don't want a drag
+                // animation.
+                mDragAnimPendingChildren.remove(view);
+            }
+            mAmbientState.onDragFinished(view);
+            updateContinuousShadowDrawing();
+
+            if (view instanceof ExpandableNotificationRow) {
+                ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+                if (row.isHeadsUp()) {
+                    mHeadsUpManager.addSwipedOutNotification(
+                            row.getStatusBarNotification().getKey());
+                }
+                isBlockingHelperShown =
+                        row.performDismissWithBlockingHelper(false /* fromAccessibility */);
+            }
+
+            if (!isBlockingHelperShown) {
+                mSwipedOutViews.add(view);
+            }
+            mFalsingManager.onNotificationDismissed();
+            if (mFalsingManager.shouldEnforceBouncer()) {
+                mStatusBar.executeRunnableDismissingKeyguard(
+                        null,
+                        null /* cancelAction */,
+                        false /* dismissShade */,
+                        true /* afterKeyguardGone */,
+                        false /* deferred */);
+            }
+        }
+
+        @Override
+        @ShadeViewRefactor(RefactorComponent.INPUT)
+        public boolean isAntiFalsingNeeded() {
+            return onKeyguard();
+        }
+
+        @Override
+        @ShadeViewRefactor(RefactorComponent.INPUT)
+        public View getChildAtPosition(MotionEvent ev) {
+            View child = NotificationStackScrollLayout.this.getChildAtPosition(ev.getX(),
+                    ev.getY());
+            if (child instanceof ExpandableNotificationRow) {
+                ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+                ExpandableNotificationRow parent = row.getNotificationParent();
+                if (parent != null && parent.areChildrenExpanded()
+                        && (parent.areGutsExposed()
+                        || mSwipeHelper.getExposedMenuView() == parent
+                        || (parent.getNotificationChildren().size() == 1
+                        && parent.isClearable()))) {
+                    // In this case the group is expanded and showing the menu for the
+                    // group, further interaction should apply to the group, not any
+                    // child notifications so we use the parent of the child. We also do the same
+                    // if we only have a single child.
+                    child = parent;
+                }
+            }
+            return child;
+        }
+
+        @Override
+        @ShadeViewRefactor(RefactorComponent.INPUT)
+        public void onBeginDrag(View v) {
+            mFalsingManager.onNotificatonStartDismissing();
+            setSwipingInProgress(true);
+            mAmbientState.onBeginDrag(v);
+            updateContinuousShadowDrawing();
+            if (mAnimationsEnabled && (mIsExpanded || !isPinnedHeadsUp(v))) {
+                mDragAnimPendingChildren.add(v);
+                mNeedsAnimation = true;
+            }
+            requestChildrenUpdate();
+        }
+
+        @Override
+        @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+        public void onChildSnappedBack(View animView, float targetLeft) {
+            mAmbientState.onDragFinished(animView);
+            updateContinuousShadowDrawing();
+            if (!mDragAnimPendingChildren.contains(animView)) {
+                if (mAnimationsEnabled) {
+                    mSnappedBackChildren.add(animView);
+                    mNeedsAnimation = true;
+                }
+                requestChildrenUpdate();
+            } else {
+                // We start the swipe and snap back in the same frame, we don't want any animation
+                mDragAnimPendingChildren.remove(animView);
+            }
+            NotificationMenuRowPlugin menuRow = mSwipeHelper.getCurrentMenuRow();
+            if (menuRow != null && targetLeft == 0) {
+                menuRow.resetMenu();
+                mSwipeHelper.clearCurrentMenuRow();
+            }
+        }
+
+        @Override
+        @ShadeViewRefactor(RefactorComponent.INPUT)
+        public boolean updateSwipeProgress(View animView, boolean dismissable,
+                float swipeProgress) {
+            // Returning true prevents alpha fading.
+            return !mFadeNotificationsOnDismiss;
+        }
+
+        @Override
+        @ShadeViewRefactor(RefactorComponent.INPUT)
+        public float getFalsingThresholdFactor() {
+            return mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
+        }
+
+        @Override
+        public boolean canChildBeDismissed(View v) {
+            return NotificationStackScrollLayout.this.canChildBeDismissed(v);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
new file mode 100644
index 0000000..028957d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the Licen
+ */
+
+
+package com.android.systemui.statusbar.notification.stack;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.SwipeHelper;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
+import com.android.systemui.statusbar.notification.ShadeViewRefactor;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.ExpandableView;
+
+@ShadeViewRefactor(ShadeViewRefactor.RefactorComponent.INPUT)
+class NotificationSwipeHelper extends SwipeHelper
+        implements NotificationSwipeActionHelper {
+    @VisibleForTesting
+    protected static final long COVER_MENU_DELAY = 4000;
+    private static final String TAG = "NotificationSwipeHelper";
+    private final Runnable mFalsingCheck;
+    private View mTranslatingParentView;
+    private View mMenuExposedView;
+    private final NotificationCallback mCallback;
+    private final NotificationMenuRowPlugin.OnMenuEventListener mMenuListener;
+
+    private static final long SWIPE_MENU_TIMING = 200;
+
+    private NotificationMenuRowPlugin mCurrMenuRow;
+
+    public NotificationSwipeHelper(int swipeDirection, NotificationCallback callback,
+            Context context, NotificationMenuRowPlugin.OnMenuEventListener menuListener) {
+        super(swipeDirection, callback, context);
+        mMenuListener = menuListener;
+        mCallback = callback;
+        mFalsingCheck = new Runnable() {
+            @Override
+            public void run() {
+                resetExposedMenuView(true /* animate */, true /* force */);
+            }
+        };
+    }
+
+    public View getTranslatingParentView() {
+        return mTranslatingParentView;
+    }
+
+    public void clearTranslatingParentView() { setTranslatingParentView(null); }
+
+    @VisibleForTesting
+    protected void setTranslatingParentView(View view) { mTranslatingParentView = view; };
+
+    public void setExposedMenuView(View view) {
+        mMenuExposedView = view;
+    }
+
+    public void clearExposedMenuView() { setExposedMenuView(null); }
+
+    public void clearCurrentMenuRow() { setCurrentMenuRow(null); }
+
+    public View getExposedMenuView() {
+        return mMenuExposedView;
+    }
+
+    public void setCurrentMenuRow(NotificationMenuRowPlugin menuRow) {
+        mCurrMenuRow = menuRow;
+    }
+
+    public NotificationMenuRowPlugin getCurrentMenuRow() {  return mCurrMenuRow; }
+
+    @VisibleForTesting
+    protected Handler getHandler() { return mHandler; }
+
+    @VisibleForTesting
+    protected Runnable getFalsingCheck() { return mFalsingCheck; };
+
+    @Override
+    public void onDownUpdate(View currView, MotionEvent ev) {
+        mTranslatingParentView = currView;
+        NotificationMenuRowPlugin menuRow = getCurrentMenuRow();
+        if (menuRow != null) {
+            menuRow.onTouchStart();
+        }
+        clearCurrentMenuRow();
+        getHandler().removeCallbacks(getFalsingCheck());
+
+        // Slide back any notifications that might be showing a menu
+        resetExposedMenuView(true /* animate */, false /* force */);
+
+        if (currView instanceof ExpandableNotificationRow) {
+            initializeRow((ExpandableNotificationRow) currView);
+        }
+    }
+
+    @VisibleForTesting
+    protected void initializeRow(ExpandableNotificationRow row) {
+        if (row.getEntry().hasFinishedInitialization()) {
+            mCurrMenuRow = row.createMenu();
+            mCurrMenuRow.setMenuClickListener(mMenuListener);
+            mCurrMenuRow.onTouchStart();
+        }
+    }
+
+    private boolean swipedEnoughToShowMenu(NotificationMenuRowPlugin menuRow) {
+        return !swipedFarEnough() && menuRow.isSwipedEnoughToShowMenu();
+    }
+
+    @Override
+    public void onMoveUpdate(View view, MotionEvent ev, float translation, float delta) {
+        getHandler().removeCallbacks(getFalsingCheck());
+        NotificationMenuRowPlugin menuRow = getCurrentMenuRow();
+        if (menuRow != null) {
+            menuRow.onTouchMove(delta);
+        }
+    }
+
+    @Override
+    public boolean handleUpEvent(MotionEvent ev, View animView, float velocity,
+            float translation) {
+        NotificationMenuRowPlugin menuRow = getCurrentMenuRow();
+        if (menuRow != null) {
+            menuRow.onTouchEnd();
+            handleMenuRowSwipe(ev, animView, velocity, menuRow);
+            return true;
+        }
+        return false;
+    }
+
+    @VisibleForTesting
+    protected void handleMenuRowSwipe(MotionEvent ev, View animView, float velocity,
+            NotificationMenuRowPlugin menuRow) {
+        if (!menuRow.shouldShowMenu()) {
+            // If the menu should not be shown, then there is no need to check if the a swipe
+            // should result in a snapping to the menu. As a result, just check if the swipe
+            // was enough to dismiss the notification.
+            if (isDismissGesture(ev)) {
+                dismiss(animView, velocity);
+            } else {
+                snapClosed(animView, velocity);
+                menuRow.onSnapClosed();
+            }
+            return;
+        }
+
+        if (menuRow.isSnappedAndOnSameSide()) {
+            // Menu was snapped to previously and we're on the same side
+            handleSwipeFromSnap(ev, animView, velocity, menuRow);
+        } else {
+            // Menu has not been snapped, or was snapped previously but is now on
+            // the opposite side.
+            handleSwipeFromNonSnap(ev, animView, velocity, menuRow);
+        }
+    }
+
+    private void handleSwipeFromNonSnap(MotionEvent ev, View animView, float velocity,
+            NotificationMenuRowPlugin menuRow) {
+        boolean isDismissGesture = isDismissGesture(ev);
+        final boolean gestureTowardsMenu = menuRow.isTowardsMenu(velocity);
+        final boolean gestureFastEnough = getEscapeVelocity() <= Math.abs(velocity);
+
+        final double timeForGesture = ev.getEventTime() - ev.getDownTime();
+        final boolean showMenuForSlowOnGoing = !menuRow.canBeDismissed()
+                && timeForGesture >= SWIPE_MENU_TIMING;
+
+        if (!isFalseGesture(ev)
+                && (swipedEnoughToShowMenu(menuRow)
+                && (!gestureFastEnough || showMenuForSlowOnGoing))
+                || (gestureTowardsMenu && !isDismissGesture)) {
+            // Menu has not been snapped to previously and this is menu revealing gesture
+            snapOpen(animView, menuRow.getMenuSnapTarget(), velocity);
+            menuRow.onSnapOpen();
+        } else if (isDismissGesture(ev) && !gestureTowardsMenu) {
+            dismiss(animView, velocity);
+            menuRow.onDismiss();
+        } else {
+            snapClosed(animView, velocity);
+            menuRow.onSnapClosed();
+        }
+    }
+
+    private void handleSwipeFromSnap(MotionEvent ev, View animView, float velocity,
+            NotificationMenuRowPlugin menuRow) {
+        boolean isDismissGesture = isDismissGesture(ev);
+
+        final boolean withinSnapMenuThreshold =
+                menuRow.isWithinSnapMenuThreshold();
+
+        if (withinSnapMenuThreshold && !isDismissGesture) {
+            // Haven't moved enough to unsnap from the menu
+            menuRow.onSnapOpen();
+            snapOpen(animView, menuRow.getMenuSnapTarget(), velocity);
+        } else if (isDismissGesture && !menuRow.shouldSnapBack()) {
+            // Only dismiss if we're not moving towards the menu
+            dismiss(animView, velocity);
+            menuRow.onDismiss();
+        } else {
+            snapClosed(animView, velocity);
+            menuRow.onSnapClosed();
+        }
+    }
+
+    @Override
+    public void dismissChild(final View view, float velocity,
+            boolean useAccelerateInterpolator) {
+        superDismissChild(view, velocity, useAccelerateInterpolator);
+        if (mCallback.isExpanded()) {
+            // We don't want to quick-dismiss when it's a heads up as this might lead to closing
+            // of the panel early.
+            mCallback.handleChildViewDismissed(view);
+        }
+        mCallback.onDismiss();
+        handleMenuCoveredOrDismissed();
+    }
+
+    @VisibleForTesting
+    protected void superDismissChild(final View view, float velocity, boolean useAccelerateInterpolator) {
+        super.dismissChild(view, velocity, useAccelerateInterpolator);
+    }
+
+    @VisibleForTesting
+    protected void superSnapChild(final View animView, final float targetLeft, float velocity) {
+        super.snapChild(animView, targetLeft, velocity);
+    }
+
+    @Override
+    public void snapChild(final View animView, final float targetLeft, float velocity) {
+        superSnapChild(animView, targetLeft, velocity);
+        mCallback.onDragCancelled(animView);
+        if (targetLeft == 0) {
+            handleMenuCoveredOrDismissed();
+        }
+    }
+
+    @Override
+    public void snooze(StatusBarNotification sbn, SnoozeOption snoozeOption) {
+        mCallback.onSnooze(sbn, snoozeOption);
+    }
+
+    @VisibleForTesting
+    protected void handleMenuCoveredOrDismissed() {
+        View exposedMenuView = getExposedMenuView();
+        if (exposedMenuView != null && exposedMenuView == mTranslatingParentView) {
+            clearExposedMenuView();
+        }
+    }
+
+    @VisibleForTesting
+    protected Animator superGetViewTranslationAnimator(View v, float target,
+            ValueAnimator.AnimatorUpdateListener listener) {
+        return super.getViewTranslationAnimator(v, target, listener);
+    }
+
+    @Override
+    public Animator getViewTranslationAnimator(View v, float target,
+            ValueAnimator.AnimatorUpdateListener listener) {
+        if (v instanceof ExpandableNotificationRow) {
+            return ((ExpandableNotificationRow) v).getTranslateViewAnimator(target, listener);
+        } else {
+            return superGetViewTranslationAnimator(v, target, listener);
+        }
+    }
+
+    @Override
+    public void setTranslation(View v, float translate) {
+        if (v instanceof ExpandableNotificationRow) {
+            ((ExpandableNotificationRow) v).setTranslation(translate);
+        } else {
+            Log.wtf(TAG, "setTranslation should only be called on an ExpandableNotificationRow.");
+        }
+    }
+
+    @Override
+    public float getTranslation(View v) {
+        if (v instanceof ExpandableNotificationRow) {
+            return ((ExpandableNotificationRow) v).getTranslation();
+        }
+        else {
+            Log.wtf(TAG, "getTranslation should only be called on an ExpandableNotificationRow.");
+            return 0f;
+        }
+    }
+
+    @Override
+    public boolean swipedFastEnough(float translation, float viewSize) {
+        return swipedFastEnough();
+    }
+
+    @Override
+    @VisibleForTesting
+    protected boolean swipedFastEnough() {
+        return super.swipedFastEnough();
+    }
+
+    @Override
+    public boolean swipedFarEnough(float translation, float viewSize) {
+        return swipedFarEnough();
+    }
+
+    @Override
+    @VisibleForTesting
+    protected boolean swipedFarEnough() {
+        return super.swipedFarEnough();
+    }
+
+    @Override
+    public void dismiss(View animView, float velocity) {
+        dismissChild(animView, velocity,
+                !swipedFastEnough() /* useAccelerateInterpolator */);
+    }
+
+    @Override
+    public void snapOpen(View animView, int targetLeft, float velocity) {
+        snapChild(animView, targetLeft, velocity);
+    }
+
+    @VisibleForTesting
+    protected void snapClosed(View animView, float velocity) {
+        snapChild(animView, 0, velocity);
+    }
+
+    @Override
+    @VisibleForTesting
+    protected float getEscapeVelocity() {
+        return super.getEscapeVelocity();
+    }
+
+    @Override
+    public float getMinDismissVelocity() {
+        return getEscapeVelocity();
+    }
+
+    public void onMenuShown(View animView) {
+        setExposedMenuView(getTranslatingParentView());
+        mCallback.onDragCancelled(animView);
+        Handler handler = getHandler();
+
+        // If we're on the lockscreen we want to false this.
+        if (mCallback.isAntiFalsingNeeded()) {
+            handler.removeCallbacks(getFalsingCheck());
+            handler.postDelayed(getFalsingCheck(), COVER_MENU_DELAY);
+        }
+    }
+
+    @VisibleForTesting
+    protected boolean shouldResetMenu(boolean force) {
+        if (mMenuExposedView == null
+                || (!force && mMenuExposedView == mTranslatingParentView)) {
+            // If no menu is showing or it's showing for this view we do nothing.
+            return false;
+        }
+        return true;
+    }
+
+    public void resetExposedMenuView(boolean animate, boolean force) {
+        if (!shouldResetMenu(force)) {
+            return;
+        }
+        final View prevMenuExposedView = getExposedMenuView();
+        if (animate) {
+            Animator anim = getViewTranslationAnimator(prevMenuExposedView,
+                    0 /* leftTarget */, null /* updateListener */);
+            if (anim != null) {
+                anim.start();
+            }
+        } else if (prevMenuExposedView instanceof ExpandableNotificationRow) {
+            ExpandableNotificationRow row = (ExpandableNotificationRow) prevMenuExposedView;
+            if (!row.isRemoved()) {
+                row.resetTranslation();
+            }
+        }
+        clearExposedMenuView();
+    }
+
+    public static boolean isTouchInView(MotionEvent ev, View view) {
+        if (view == null) {
+            return false;
+        }
+        final int height = (view instanceof ExpandableView)
+                ? ((ExpandableView) view).getActualHeight()
+                : view.getHeight();
+        final int rx = (int) ev.getRawX();
+        final int ry = (int) ev.getRawY();
+        int[] temp = new int[2];
+        view.getLocationOnScreen(temp);
+        final int x = temp[0];
+        final int y = temp[1];
+        Rect rect = new Rect(x, y, x + view.getWidth(), y + height);
+        boolean ret = rect.contains(rx, ry);
+        return ret;
+    }
+
+    public interface NotificationCallback extends SwipeHelper.Callback{
+        boolean isExpanded();
+
+        void handleChildViewDismissed(View view);
+
+        void onSnooze(StatusBarNotification sbn, SnoozeOption snoozeOption);
+
+        void onDismiss();
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index 235ff2b..c32dcea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -67,6 +67,10 @@
         mView.setBackground(mBarBackground);
     }
 
+    public void destroy() {
+        // To be overridden
+    }
+
     public int getMode() {
         return mMode;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
index 81b596c..424acfd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
@@ -34,9 +34,11 @@
     private val inCarMode: Boolean
     private var uiMode: Int = 0
     private var localeList: LocaleList? = null
+    private val context: Context
 
     init {
         val currentConfig = context.resources.configuration
+        this.context = context
         fontScale = currentConfig.fontScale
         density = currentConfig.densityDpi
         inCarMode = currentConfig.uiMode and Configuration.UI_MODE_TYPE_MASK ==
@@ -82,6 +84,10 @@
         }
 
         if (uiModeChanged) {
+            // We need to force the style re-evaluation to make sure that it's up to date
+            // and attrs were reloaded.
+            context.theme.applyStyle(context.themeResId, true)
+
             this.uiMode = uiMode
             listeners.filterForEach({ this.listeners.contains(it) }) {
                 it.onUiModeChanged()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java
new file mode 100644
index 0000000..c7ab27b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.annotation.DrawableRes;
+import android.annotation.IdRes;
+import android.content.Context;
+import android.view.View;
+import com.android.systemui.statusbar.policy.KeyButtonDrawable;
+import com.android.systemui.statusbar.policy.KeyButtonView;
+
+/**
+ * Simple contextual button that is added to the {@link ContextualButtonGroup}. Extend if need extra
+ * functionality.
+ */
+public class ContextualButton extends ButtonDispatcher {
+
+    protected final @DrawableRes int mIconResId;
+
+    /**
+      * Create a contextual button that will use a {@link KeyButtonView} and
+      * {@link KeyButtonDrawable} get and show the button from xml to its icon drawable.
+      * @param buttonResId the button view from xml layout
+      * @param iconResId icon resource to be used
+      */
+    public ContextualButton(@IdRes int buttonResId, @DrawableRes int iconResId) {
+        super(buttonResId);
+        mIconResId = iconResId;
+    }
+
+    /**
+     * Reload the drawable from resource id, should reapply the previous dark intensity.
+     */
+    public void updateIcon() {
+        final KeyButtonDrawable currentDrawable = getImageDrawable();
+        KeyButtonDrawable drawable = getNewDrawable();
+        if (currentDrawable != null) {
+            drawable.setDarkIntensity(currentDrawable.getDarkIntensity());
+        }
+        setImageDrawable(drawable);
+    }
+
+    @Override
+    public void setVisibility(int visibility) {
+        super.setVisibility(visibility);
+
+        // Stop any active animations if hidden
+        final KeyButtonDrawable currentDrawable = getImageDrawable();
+        if (visibility != View.VISIBLE && currentDrawable != null && currentDrawable.canAnimate()) {
+            currentDrawable.clearAnimationCallbacks();
+            currentDrawable.resetAnimation();
+        }
+    }
+
+    protected KeyButtonDrawable getNewDrawable() {
+        return KeyButtonDrawable.create(getContext().getApplicationContext(), mIconResId,
+                false /* shadow */);
+    }
+
+    /**
+     * This context is from the view that could be stale after rotation or config change. To get
+     * correct resources use getApplicationContext() as well.
+     * @return current view context
+     */
+    protected Context getContext() {
+        return getCurrentView().getContext();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButtonGroup.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButtonGroup.java
new file mode 100644
index 0000000..1b03966
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButtonGroup.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.annotation.IdRes;
+import android.annotation.NonNull;
+import android.view.View;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ContextualButtonGroup extends ButtonDispatcher {
+    private static final int INVALID_INDEX = -1;
+
+    // List of pairs that contains the button and if the button was visible within this group
+    private final List<ButtonData> mButtonData = new ArrayList<>();
+
+    public ContextualButtonGroup(@IdRes int containerId) {
+        super(containerId);
+    }
+
+    /**
+     * Add a contextual button to the group. The order of adding increases in its priority. The
+     * priority is used to determine which button should be visible when setting multiple button's
+     * visibility {@see setButtonVisiblity}.
+     * @param button the button added to the group
+     */
+    public void addButton(@NonNull ContextualButton button) {
+        mButtonData.add(new ButtonData(button));
+    }
+
+    public ContextualButton getContextButton(@IdRes int buttonResId) {
+        int index = getContextButtonIndex(buttonResId);
+        if (index != INVALID_INDEX) {
+            return mButtonData.get(index).button;
+        }
+        return null;
+    }
+
+    public ContextualButton getVisibleContextButton() {
+        for (int i = mButtonData.size() - 1; i >= 0; --i) {
+            if (mButtonData.get(i).markedVisible) {
+                return mButtonData.get(i).button;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Set the visibility of the button by {@param buttonResId} with {@param visible}. Only one
+     * button is shown at a time. The input button will only show up if it has higher priority than
+     * a previous button, otherwise it will be marked as visible and shown later if all higher
+     * priority buttons are invisible. Therefore hiding a button will show the next marked visible
+     * button. This group's view will be visible if at least one button is visible.
+     * @return if the button is visible after operation
+     * @throws RuntimeException if the input id does not match any of the ids in the group
+     */
+    public int setButtonVisiblity(@IdRes int buttonResId, boolean visible) {
+        final int index = getContextButtonIndex(buttonResId);
+        if (index == INVALID_INDEX) {
+            throw new RuntimeException("Cannot find the button id of " + buttonResId
+                    + " in context group");
+        }
+        setVisibility(View.INVISIBLE);
+        mButtonData.get(index).markedVisible = visible;
+
+        // Make all buttons invisible except the first markedVisible button
+        boolean alreadyFoundVisibleButton = false;
+        int i = mButtonData.size() - 1;
+        for (; i >= 0; --i) {
+            final ButtonData buttonData = mButtonData.get(i);
+            if (!alreadyFoundVisibleButton && buttonData.markedVisible) {
+                buttonData.setVisibility(View.VISIBLE);
+                setVisibility(View.VISIBLE);
+                alreadyFoundVisibleButton = true;
+            } else {
+                buttonData.setVisibility(View.INVISIBLE);
+            }
+        }
+        return mButtonData.get(index).button.getVisibility();
+    }
+
+    /**
+     * See if button is group visible. Group visible determines if a button can be visible when
+     * higher priority buttons go invisible.
+     * @param buttonResId the button to see if it is group visible
+     * @return true if button is group visible
+     */
+    public boolean isButtonVisibleWithinGroup(@IdRes int buttonResId) {
+        final int index = getContextButtonIndex(buttonResId);
+        return index != INVALID_INDEX && mButtonData.get(index).markedVisible;
+    }
+
+    /**
+     * Update all the icons that are attached to this group. This will get all the buttons to update
+     * their icons for their buttons.
+     */
+    public void updateIcons() {
+        for (ButtonData data : mButtonData) {
+            data.button.updateIcon();
+        }
+    }
+
+    public void dump(PrintWriter pw) {
+        pw.println("ContextualButtonGroup {");
+        pw.println("      getVisibleContextButton(): " + getVisibleContextButton());
+        pw.println("      isVisible(): " + isVisible());
+        pw.println("      mButtonData [ ");
+        for (int i = mButtonData.size() - 1; i >= 0; --i) {
+            final ButtonData data = mButtonData.get(i);
+            pw.println("            " + i + ": markedVisible=" + data.markedVisible
+                    + " visible=" + data.button.getVisibility()
+                    + " alpha=" + data.button.getAlpha());
+        }
+        pw.println("      ]");
+        pw.println("    }");
+    }
+
+    private int getContextButtonIndex(@IdRes int buttonResId) {
+        for (int i = 0; i < mButtonData.size(); ++i) {
+            if (mButtonData.get(i).button.getId() == buttonResId) {
+                return i;
+            }
+        }
+        return INVALID_INDEX;
+    }
+
+    private final static class ButtonData {
+        ContextualButton button;
+        boolean markedVisible;
+
+        ButtonData(ContextualButton button) {
+            this.button = button;
+            this.markedVisible = false;
+        }
+
+        void setVisibility(int visiblity) {
+            button.setVisibility(visiblity);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index 0d3ba77..25db4f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -63,9 +63,14 @@
             if (!mDozing) {
                 return;
             }
-            mHandler.postDelayed(mPulseOut, mDozeParameters.getPulseVisibleDuration());
-            mHandler.postDelayed(mPulseOutExtended,
-                    mDozeParameters.getPulseVisibleDurationExtended());
+            // All pulses except notifications should time out on their own.  Pulses due to
+            // notifications should instead be managed externally based off the notification's
+            // lifetime.
+            if (mPulseReason != DozeLog.PULSE_REASON_NOTIFICATION) {
+                mHandler.postDelayed(mPulseOut, mDozeParameters.getPulseVisibleDuration());
+                mHandler.postDelayed(mPulseOutExtended,
+                        mDozeParameters.getPulseVisibleDurationExtended());
+            }
             mFullyPulsing = true;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index 4a05989..cfc3271 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -177,7 +177,7 @@
             mReleaseOnExpandFinish = false;
         } else {
             for (NotificationData.Entry entry : mEntriesToRemoveAfterExpand) {
-                if (contains(entry.key)) {
+                if (isAlerting(entry.key)) {
                     // Maybe the heads-up was removed already
                     removeAlertEntry(entry.key);
                 }
@@ -345,7 +345,7 @@
     public void onReorderingAllowed() {
         mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(false);
         for (NotificationData.Entry entry : mEntriesToRemoveWhenReorderingAllowed) {
-            if (contains(entry.key)) {
+            if (isAlerting(entry.key)) {
                 // Maybe the heads-up was removed already
                 removeAlertEntry(entry.key);
             }
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 d89bcda..f667726 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -19,6 +19,7 @@
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
 import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 
+import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
 import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_BUTTON;
 import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_UNLOCK;
 import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_RIGHT_BUTTON;
@@ -171,7 +172,6 @@
     private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
     private boolean mDozing;
     private int mIndicationBottomMargin;
-    private int mIndicationBottomMarginAmbient;
     private float mDarkAmount;
     private int mBurnInXOffset;
     private int mBurnInYOffset;
@@ -246,10 +246,8 @@
         mIndicationText = findViewById(R.id.keyguard_indication_text);
         mIndicationBottomMargin = getResources().getDimensionPixelSize(
                 R.dimen.keyguard_indication_margin_bottom);
-        mIndicationBottomMarginAmbient = getResources().getDimensionPixelSize(
-                R.dimen.keyguard_indication_margin_bottom_ambient);
         mBurnInYOffset = getResources().getDimensionPixelSize(
-                R.dimen.charging_indication_burn_in_prevention_offset_y);
+                R.dimen.default_burn_in_prevention_offset);
         updateCameraVisibility();
         mUnlockMethodCache = UnlockMethodCache.getInstance(getContext());
         mUnlockMethodCache.addListener(this);
@@ -320,10 +318,8 @@
         super.onConfigurationChanged(newConfig);
         mIndicationBottomMargin = getResources().getDimensionPixelSize(
                 R.dimen.keyguard_indication_margin_bottom);
-        mIndicationBottomMarginAmbient = getResources().getDimensionPixelSize(
-                R.dimen.keyguard_indication_margin_bottom_ambient);
         mBurnInYOffset = getResources().getDimensionPixelSize(
-                R.dimen.charging_indication_burn_in_prevention_offset_y);
+                R.dimen.default_burn_in_prevention_offset);
         MarginLayoutParams mlp = (MarginLayoutParams) mIndicationArea.getLayoutParams();
         if (mlp.bottomMargin != mIndicationBottomMargin) {
             mlp.bottomMargin = mIndicationBottomMargin;
@@ -567,9 +563,7 @@
             return;
         }
         mDarkAmount = darkAmount;
-        mIndicationArea.setAlpha(MathUtils.lerp(1f, 0.7f, darkAmount));
-        mIndicationArea.setTranslationY(MathUtils.lerp(0,
-                mIndicationBottomMargin - mIndicationBottomMarginAmbient, darkAmount));
+        mIndicationArea.setAlpha(1f - darkAmount);
     }
 
     private static boolean isSuccessfulLaunch(int result) {
@@ -842,10 +836,10 @@
 
     public void dozeTimeTick() {
         if (mDarkAmount == 1) {
-            // Move indication every minute to avoid burn-in
-            int dozeTranslation = mIndicationBottomMargin - mIndicationBottomMarginAmbient;
-            int burnInYOffset = (int) (-mBurnInYOffset + Math.random() * mBurnInYOffset * 2);
-            mIndicationArea.setTranslationY(dozeTranslation + burnInYOffset);
+            // Move views every minute to avoid burn-in
+            int burnInYOffset = getBurnInOffset(mBurnInYOffset * 2, false /* xAxis */)
+                    - mBurnInYOffset;
+            mLockIcon.setTranslationY(burnInYOffset);
         }
     }
 
@@ -854,7 +848,7 @@
             return;
         }
         mBurnInXOffset = burnInXOffset;
-        mIndicationArea.setTranslationX(burnInXOffset);
+        mLockIcon.setTranslationX(burnInXOffset);
     }
 
     private class DefaultLeftButton implements IntentButton {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 042e4ff..33bc164 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
 import static com.android.systemui.statusbar.notification.NotificationUtils.interpolate;
 
 import android.content.res.Resources;
@@ -30,10 +31,6 @@
  */
 public class KeyguardClockPositionAlgorithm {
 
-    private static final long MILLIS_PER_MINUTES = 1000 * 60;
-    private static final float BURN_IN_PREVENTION_PERIOD_Y = 521;
-    private static final float BURN_IN_PREVENTION_PERIOD_X = 83;
-
     /**
      * How much the clock height influences the shade position.
      * 0 means nothing, 1 means move the shade up by the height of the clock
@@ -228,34 +225,15 @@
     }
 
     private float burnInPreventionOffsetY() {
-        return zigzag(System.currentTimeMillis() / MILLIS_PER_MINUTES,
-                mBurnInPreventionOffsetY * 2,
-                BURN_IN_PREVENTION_PERIOD_Y)
+        return getBurnInOffset(mBurnInPreventionOffsetY * 2, false /* xAxis */)
                 - mBurnInPreventionOffsetY;
     }
 
     private float burnInPreventionOffsetX() {
-        return zigzag(System.currentTimeMillis() / MILLIS_PER_MINUTES,
-                mBurnInPreventionOffsetX * 2,
-                BURN_IN_PREVENTION_PERIOD_X)
+        return getBurnInOffset(mBurnInPreventionOffsetX * 2, true /* xAxis */)
                 - mBurnInPreventionOffsetX;
     }
 
-    /**
-     * Implements a continuous, piecewise linear, periodic zig-zag function
-     *
-     * Can be thought of as a linear approximation of abs(sin(x)))
-     *
-     * @param period period of the function, ie. zigzag(x + period) == zigzag(x)
-     * @param amplitude maximum value of the function
-     * @return a value between 0 and amplitude
-     */
-    private float zigzag(float x, float amplitude, float period) {
-        float xprime = (x % period) / (period / 2);
-        float interpolationAmount = (xprime <= 1) ? xprime : (2 - xprime);
-        return interpolate(0, amplitude, interpolationAmount);
-    }
-
     public static class Result {
 
         /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 5630da6..7c84df9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.phone;
 
 import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFromDirection;
+import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
 
 import android.annotation.ColorInt;
 import android.content.Context;
@@ -70,16 +71,18 @@
     private static final int LAYOUT_CUTOUT = 1;
     private static final int LAYOUT_NO_CUTOUT = 2;
 
+    private final Rect mEmptyRect = new Rect(0, 0, 0, 0);
+
     private boolean mShowPercentAvailable;
     private boolean mBatteryCharging;
     private boolean mKeyguardUserSwitcherShowing;
     private boolean mBatteryListening;
 
     private TextView mCarrierLabel;
-    private View mSystemIconsSuperContainer;
     private MultiUserSwitch mMultiUserSwitch;
     private ImageView mMultiUserAvatar;
     private BatteryMeterView mBatteryView;
+    private StatusIconContainer mStatusIconContainer;
 
     private BatteryController mBatteryController;
     private KeyguardUserSwitcher mKeyguardUserSwitcher;
@@ -99,6 +102,18 @@
      */
     private int mCutoutSideNudge = 0;
 
+    /**
+     * How much to move icons to avoid burn in.
+     */
+    private int mBurnInOffset;
+    private int mCurrentBurnInOffsetX;
+    private int mCurrentBurnInOffsetY;
+
+    /**
+     * Ratio representing being in ambient mode or not.
+     */
+    private float mDarkAmount;
+
     public KeyguardStatusBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -113,6 +128,7 @@
         mBatteryView = mSystemIconsContainer.findViewById(R.id.battery);
         mCutoutSpace = findViewById(R.id.cutout_space_view);
         mStatusIconArea = findViewById(R.id.status_icon_area);
+        mStatusIconContainer = findViewById(R.id.statusIcons);
 
         loadDimens();
         updateUserSwitcher();
@@ -169,6 +185,8 @@
                 R.dimen.system_icons_super_container_avatarless_margin_end);
         mCutoutSideNudge = getResources().getDimensionPixelSize(
                 R.dimen.display_cutout_margin_consumption);
+        mBurnInOffset = getResources().getDimensionPixelSize(
+                R.dimen.default_burn_in_prevention_offset);
         mShowPercentAvailable = getContext().getResources().getBoolean(
                 com.android.internal.R.bool.config_battery_percentage_setting_available);
     }
@@ -440,6 +458,14 @@
     }
 
     public void onThemeChanged() {
+        mBatteryView.setColorsFromContext(mContext);
+        updateIconsAndTextColors();
+        // Reload user avatar
+        ((UserInfoControllerImpl) Dependency.get(UserInfoController.class))
+                .onDensityOrFontScaleChanged();
+    }
+
+    private void updateIconsAndTextColors() {
         @ColorInt int textColor = Utils.getColorAttrDefaultColor(mContext,
                 R.attr.wallpaperTextColor);
         @ColorInt int iconColor = Utils.getColorStateListDefaultColor(mContext,
@@ -448,14 +474,9 @@
         float intensity = textColor == Color.WHITE ? 0 : 1;
         mCarrierLabel.setTextColor(iconColor);
         mIconManager.setTint(iconColor);
-        mBatteryView.setColorsFromContext(mContext);
-        Rect tintArea = new Rect(0, 0, 0, 0);
 
-        applyDarkness(R.id.battery, tintArea, intensity, iconColor);
-        applyDarkness(R.id.clock, tintArea, intensity, iconColor);
-        // Reload user avatar
-        ((UserInfoControllerImpl) Dependency.get(UserInfoController.class))
-                .onDensityOrFontScaleChanged();
+        applyDarkness(R.id.battery, mEmptyRect, intensity * (1f - mDarkAmount), iconColor);
+        applyDarkness(R.id.clock, mEmptyRect, intensity, iconColor);
     }
 
     private void applyDarkness(int id, Rect tintArea, float intensity, int color) {
@@ -475,4 +496,32 @@
             mBatteryView.dump(fd, pw, args);
         }
     }
+
+    public void setDarkAmount(float darkAmount) {
+        mDarkAmount = darkAmount;
+        if (darkAmount == 0) {
+            dozeTimeTick();
+        }
+        updateDozeState();
+    }
+
+    public void dozeTimeTick() {
+        mCurrentBurnInOffsetX = getBurnInOffset(mBurnInOffset, true /* xAxis */);
+        mCurrentBurnInOffsetY = getBurnInOffset(mBurnInOffset, false /* xAxis */);
+        updateDozeState();
+    }
+
+    private void updateDozeState() {
+        float alpha = 1f - mDarkAmount;
+        int visibility = alpha != 0f ? VISIBLE : INVISIBLE;
+        mCarrierLabel.setAlpha(alpha);
+        mCarrierLabel.setVisibility(visibility);
+        mStatusIconContainer.setAlpha(alpha);
+        mStatusIconContainer.setVisibility(visibility);
+
+        mSystemIconsContainer.setTranslationX(-mCurrentBurnInOffsetX * mDarkAmount);
+        mSystemIconsContainer.setTranslationY(mCurrentBurnInOffsetY * mDarkAmount);
+        updateIconsAndTextColors();
+    }
+
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 10b019d..9c579da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -35,6 +35,7 @@
 import android.animation.ObjectAnimator;
 import android.annotation.IdRes;
 import android.annotation.Nullable;
+import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
 import android.app.Fragment;
 import android.app.IActivityManager;
@@ -88,8 +89,8 @@
 import com.android.systemui.fragments.FragmentHostManager;
 import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
 import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.CommandQueue.Callbacks;
@@ -284,7 +285,7 @@
         mNavigationBarView = (NavigationBarView) view;
 
         mNavigationBarView.setDisabledFlags(mDisabledFlags1);
-        mNavigationBarView.setComponents(mRecents, mDivider, mStatusBar.getPanel());
+        mNavigationBarView.setComponents(mStatusBar.getPanel());
         mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged);
         mNavigationBarView.setOnTouchListener(this::onNavigationTouch);
         if (savedInstanceState != null) {
@@ -307,7 +308,10 @@
     @Override
     public void onDestroyView() {
         super.onDestroyView();
-        mNavigationBarView.getLightTransitionsController().destroy(getContext());
+        if (mNavigationBarView != null) {
+            mNavigationBarView.getBarTransitions().destroy();
+            mNavigationBarView.getLightTransitionsController().destroy(getContext());
+        }
         mOverviewProxyService.removeCallback(mOverviewProxyListener);
         getContext().unregisterReceiver(mBroadcastReceiver);
     }
@@ -460,7 +464,7 @@
                 style = rotationCCW ? R.style.RotateButtonCCWStart0 :
                         R.style.RotateButtonCWStart0;
             }
-            mNavigationBarView.updateRotateSuggestionButtonStyle(style, true);
+            mNavigationBarView.updateRotateSuggestionButtonStyle(style);
         }
 
         if (mNavigationBarWindowState != WINDOW_STATE_SHOWING) {
@@ -943,7 +947,7 @@
     private boolean onLongPressRecents() {
         if (mRecents == null || !ActivityTaskManager.supportsMultiWindow(getContext())
                 || !mDivider.getView().getSnapAlgorithm().isSplitScreenFeasible()
-                || Recents.getConfiguration().isLowRamDevice
+                || ActivityManager.isLowRamDeviceStatic()
                 // If we are connected to the overview service, then disable the recents button
                 || mOverviewProxyService.getProxy() != null) {
             return false;
@@ -1107,7 +1111,7 @@
         }
     };
 
-    class TaskStackListenerImpl extends SysUiTaskStackChangeListener {
+    class TaskStackListenerImpl extends TaskStackChangeListener {
         // Invalidate any rotation suggestion on task change or activity orientation change
         // Note: all callbacks happen on main thread
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index 8c02e1f..62d2099 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -16,93 +16,36 @@
 
 package com.android.systemui.statusbar.phone;
 
-import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
-import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
-import static android.view.WindowManager.DOCKED_INVALID;
-import static android.view.WindowManager.DOCKED_LEFT;
-import static android.view.WindowManager.DOCKED_TOP;
-
-import android.app.ActivityManager;
 import android.content.Context;
-import android.content.res.Resources;
 import android.graphics.Canvas;
-import android.graphics.Rect;
 import android.view.MotionEvent;
-import android.view.VelocityTracker;
 import android.view.View;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
-import com.android.systemui.Dependency;
-import com.android.systemui.R;
-import com.android.systemui.RecentsComponent;
 import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
-import com.android.systemui.stackdivider.Divider;
-import com.android.systemui.tuner.TunerService;
 
 /**
- * Class to detect gestures on the navigation bar.
+ * TODO: Remove and replace with QuickStepController
  */
-public class NavigationBarGestureHelper implements TunerService.Tunable, GestureHelper {
+public class NavigationBarGestureHelper implements GestureHelper {
 
-    private static final String TAG = "NavBarGestureHelper";
-    private static final String KEY_DOCK_WINDOW_GESTURE = "overview_nav_bar_gesture";
-    /**
-     * When dragging from the navigation bar, we drag in recents.
-     */
-    public static final int DRAG_MODE_NONE = -1;
+    private static final String TAG = "NavigationBarGestureHelper";
 
-    /**
-     * When dragging from the navigation bar, we drag in recents.
-     */
-    public static final int DRAG_MODE_RECENTS = 0;
-
-    /**
-     * When dragging from the navigation bar, we drag the divider.
-     */
-    public static final int DRAG_MODE_DIVIDER = 1;
-
-    private RecentsComponent mRecentsComponent;
-    private Divider mDivider;
-    private Context mContext;
     private NavigationBarView mNavigationBarView;
-    private boolean mIsVertical;
 
     private final QuickStepController mQuickStepController;
-    private final int mScrollTouchSlop;
     private final StatusBar mStatusBar;
-    private int mTouchDownX;
-    private int mTouchDownY;
-    private boolean mDownOnRecents;
-    private VelocityTracker mVelocityTracker;
-
-    private boolean mDockWindowEnabled;
-    private boolean mDockWindowTouchSlopExceeded;
-    private int mDragMode;
 
     public NavigationBarGestureHelper(Context context) {
-        mContext = context;
         mStatusBar = SysUiServiceProvider.getComponent(context, StatusBar.class);
-        Resources r = context.getResources();
-        mScrollTouchSlop = r.getDimensionPixelSize(R.dimen.navigation_bar_min_swipe_distance);
         mQuickStepController = new QuickStepController(context);
-        Dependency.get(TunerService.class).addTunable(this, KEY_DOCK_WINDOW_GESTURE);
     }
 
-    public void destroy() {
-        Dependency.get(TunerService.class).removeTunable(this);
-    }
-
-    public void setComponents(RecentsComponent recentsComponent, Divider divider,
-            NavigationBarView navigationBarView) {
-        mRecentsComponent = recentsComponent;
-        mDivider = divider;
+    public void setComponents(NavigationBarView navigationBarView) {
         mNavigationBarView = navigationBarView;
         mQuickStepController.setComponents(mNavigationBarView);
     }
 
     public void setBarState(boolean isVertical, boolean isRTL) {
-        mIsVertical = isVertical;
         mQuickStepController.setBarState(isVertical, isRTL);
     }
 
@@ -110,22 +53,14 @@
         if (!canHandleGestures()) {
             return false;
         }
-        boolean result = mQuickStepController.onInterceptTouchEvent(event);
-        if (mDockWindowEnabled) {
-            result |= interceptDockWindowEvent(event);
-        }
-        return result;
+        return mQuickStepController.onInterceptTouchEvent(event);
     }
 
     public boolean onTouchEvent(MotionEvent event) {
         if (!canHandleGestures()) {
             return false;
         }
-        boolean result = mQuickStepController.onTouchEvent(event);
-        if (mDockWindowEnabled) {
-            result |= handleDockWindowEvent(event);
-        }
-        return result;
+        return mQuickStepController.onTouchEvent(event);
     }
 
     public void onDraw(Canvas canvas) {
@@ -144,152 +79,7 @@
         mQuickStepController.onNavigationButtonLongPress(v);
     }
 
-    private boolean interceptDockWindowEvent(MotionEvent event) {
-        switch (event.getActionMasked()) {
-            case MotionEvent.ACTION_DOWN:
-                handleDragActionDownEvent(event);
-                break;
-            case MotionEvent.ACTION_MOVE:
-                return handleDragActionMoveEvent(event);
-            case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_CANCEL:
-                handleDragActionUpEvent(event);
-                break;
-        }
-        return false;
-    }
-
-    private boolean handleDockWindowEvent(MotionEvent event) {
-        switch (event.getActionMasked()) {
-            case MotionEvent.ACTION_DOWN:
-                handleDragActionDownEvent(event);
-                break;
-            case MotionEvent.ACTION_MOVE:
-                handleDragActionMoveEvent(event);
-                break;
-            case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_CANCEL:
-                handleDragActionUpEvent(event);
-                break;
-        }
-        return true;
-    }
-
-    private void handleDragActionDownEvent(MotionEvent event) {
-        mVelocityTracker = VelocityTracker.obtain();
-        mVelocityTracker.addMovement(event);
-        mDockWindowTouchSlopExceeded = false;
-        mTouchDownX = (int) event.getX();
-        mTouchDownY = (int) event.getY();
-
-        if (mNavigationBarView != null) {
-            View recentsButton = mNavigationBarView.getRecentsButton().getCurrentView();
-            if (recentsButton != null) {
-                mDownOnRecents = mTouchDownX >= recentsButton.getLeft()
-                        && mTouchDownX <= recentsButton.getRight()
-                        && mTouchDownY >= recentsButton.getTop()
-                        && mTouchDownY <= recentsButton.getBottom();
-            } else {
-                mDownOnRecents = false;
-            }
-        }
-    }
-
-    private boolean handleDragActionMoveEvent(MotionEvent event) {
-        mVelocityTracker.addMovement(event);
-        int x = (int) event.getX();
-        int y = (int) event.getY();
-        int xDiff = Math.abs(x - mTouchDownX);
-        int yDiff = Math.abs(y - mTouchDownY);
-        if (mDivider == null || mRecentsComponent == null) {
-            return false;
-        }
-        if (!mDockWindowTouchSlopExceeded) {
-            boolean touchSlopExceeded = !mIsVertical
-                    ? yDiff > mScrollTouchSlop && yDiff > xDiff
-                    : xDiff > mScrollTouchSlop && xDiff > yDiff;
-            if (mDownOnRecents && touchSlopExceeded
-                    && mDivider.getView().getWindowManagerProxy().getDockSide() == DOCKED_INVALID) {
-                Rect initialBounds = null;
-                int dragMode = calculateDragMode();
-                int createMode = SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
-                if (dragMode == DRAG_MODE_DIVIDER) {
-                    initialBounds = new Rect();
-                    mDivider.getView().calculateBoundsForPosition(mIsVertical
-                                    ? (int) event.getRawX()
-                                    : (int) event.getRawY(),
-                            mDivider.getView().isHorizontalDivision()
-                                    ? DOCKED_TOP
-                                    : DOCKED_LEFT,
-                            initialBounds);
-                } else if (dragMode == DRAG_MODE_RECENTS && mTouchDownX
-                        < mContext.getResources().getDisplayMetrics().widthPixels / 2) {
-                    createMode = SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
-                }
-                boolean docked = mRecentsComponent.splitPrimaryTask(dragMode, createMode,
-                        initialBounds, MetricsEvent.ACTION_WINDOW_DOCK_SWIPE);
-                if (docked) {
-                    mDragMode = dragMode;
-                    if (mDragMode == DRAG_MODE_DIVIDER) {
-                        mDivider.getView().startDragging(false /* animate */, true /* touching*/);
-                    }
-                    mDockWindowTouchSlopExceeded = true;
-                    return true;
-                }
-            }
-        } else {
-            if (mDragMode == DRAG_MODE_DIVIDER) {
-                int position = !mIsVertical ? (int) event.getRawY() : (int) event.getRawX();
-                SnapTarget snapTarget = mDivider.getView().getSnapAlgorithm()
-                        .calculateSnapTarget(position, 0f /* velocity */, false /* hardDismiss */);
-                mDivider.getView().resizeStack(position, snapTarget.position, snapTarget);
-            } else if (mDragMode == DRAG_MODE_RECENTS) {
-                mRecentsComponent.onDraggingInRecents(event.getRawY());
-            }
-        }
-        return false;
-    }
-
-    private void handleDragActionUpEvent(MotionEvent event) {
-        mVelocityTracker.addMovement(event);
-        mVelocityTracker.computeCurrentVelocity(1000);
-        if (mDockWindowTouchSlopExceeded && mDivider != null && mRecentsComponent != null) {
-            if (mDragMode == DRAG_MODE_DIVIDER) {
-                mDivider.getView().stopDragging(mIsVertical
-                                ? (int) event.getRawX()
-                                : (int) event.getRawY(),
-                        mIsVertical
-                                ? mVelocityTracker.getXVelocity()
-                                : mVelocityTracker.getYVelocity(),
-                        true /* avoidDismissStart */, false /* logMetrics */);
-            } else if (mDragMode == DRAG_MODE_RECENTS) {
-                mRecentsComponent.onDraggingInRecentsEnded(mVelocityTracker.getYVelocity());
-            }
-        }
-        mVelocityTracker.recycle();
-        mVelocityTracker = null;
-    }
-
     private boolean canHandleGestures() {
         return !mStatusBar.isKeyguardShowing();
     }
-
-    private int calculateDragMode() {
-        if (mIsVertical && !mDivider.getView().isHorizontalDivision()) {
-            return DRAG_MODE_DIVIDER;
-        }
-        if (!mIsVertical && mDivider.getView().isHorizontalDivision()) {
-            return DRAG_MODE_DIVIDER;
-        }
-        return DRAG_MODE_RECENTS;
-    }
-
-    @Override
-    public void onTuningChanged(String key, String newValue) {
-        switch (key) {
-            case KEY_DOCK_WINDOW_GESTURE:
-                mDockWindowEnabled = newValue != null && (Integer.parseInt(newValue) != 0);
-                break;
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
index e09d31c..d58b554 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -44,6 +44,17 @@
     private boolean mAutoDim;
     private View mNavButtons;
 
+    private final Handler mHandler = Handler.getMain();
+    private final IWallpaperVisibilityListener mWallpaperVisibilityListener =
+            new IWallpaperVisibilityListener.Stub() {
+        @Override
+        public void onWallpaperVisibilityChanged(boolean newVisibility,
+        int displayId) throws RemoteException {
+            mWallpaperVisible = newVisibility;
+            mHandler.post(() -> applyLightsOut(true, false));
+        }
+    };
+
     public NavigationBarTransitions(NavigationBarView view) {
         super(view, R.drawable.nav_background);
         mView = view;
@@ -55,17 +66,9 @@
                 .getBoolean(R.bool.config_navigation_bar_enable_auto_dim_no_visible_wallpaper);
 
         IWindowManager windowManagerService = Dependency.get(IWindowManager.class);
-        Handler handler = Handler.getMain();
         try {
             mWallpaperVisible = windowManagerService.registerWallpaperVisibilityListener(
-                new IWallpaperVisibilityListener.Stub() {
-                    @Override
-                    public void onWallpaperVisibilityChanged(boolean newVisibility,
-                            int displayId) throws RemoteException {
-                        mWallpaperVisible = newVisibility;
-                        handler.post(() -> applyLightsOut(true, false));
-                    }
-                }, Display.DEFAULT_DISPLAY);
+                    mWallpaperVisibilityListener, Display.DEFAULT_DISPLAY);
         } catch (RemoteException e) {
         }
         mView.addOnLayoutChangeListener(
@@ -88,6 +91,16 @@
     }
 
     @Override
+    public void destroy() {
+        IWindowManager windowManagerService = Dependency.get(IWindowManager.class);
+        try {
+            windowManagerService.unregisterWallpaperVisibilityListener(mWallpaperVisibilityListener,
+                    Display.DEFAULT_DISPLAY);
+        } catch (RemoteException e) {
+        }
+    }
+
+    @Override
     public void setAutoDim(boolean autoDim) {
         if (mAutoDim == autoDim) return;
         mAutoDim = autoDim;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 2141016..e5c9100 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -36,8 +36,6 @@
 import android.graphics.Canvas;
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.graphics.drawable.AnimatedVectorDrawable;
-import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
@@ -46,7 +44,6 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.SparseArray;
-import android.view.ContextThemeWrapper;
 import android.view.Display;
 import android.view.MotionEvent;
 import android.view.Surface;
@@ -59,7 +56,6 @@
 import android.view.inputmethod.InputMethodManager;
 import android.widget.FrameLayout;
 
-import com.android.settingslib.Utils;
 import com.android.systemui.Dependency;
 import com.android.systemui.DockedStackExistsListener;
 import com.android.systemui.Interpolators;
@@ -106,10 +102,7 @@
     boolean mVertical;
     private int mCurrentRotation = -1;
 
-    boolean mShowMenu;
-    boolean mShowAccessibilityButton;
     boolean mLongClickableAccessibilityButton;
-    boolean mShowRotateButton;
     int mDisabledFlags = 0;
     int mNavigationIconHints = 0;
 
@@ -125,10 +118,6 @@
     private KeyButtonDrawable mHomeDefaultIcon;
     private KeyButtonDrawable mRecentIcon;
     private KeyButtonDrawable mDockedIcon;
-    private KeyButtonDrawable mImeIcon;
-    private KeyButtonDrawable mMenuIcon;
-    private KeyButtonDrawable mAccessibilityIcon;
-    private KeyButtonDrawable mRotateSuggestionIcon;
 
     private GestureHelper mGestureHelper;
     private final DeadZone mDeadZone;
@@ -151,16 +140,13 @@
     private boolean mDockedStackExists;
 
     private final SparseArray<ButtonDispatcher> mButtonDispatchers = new SparseArray<>();
+    private final ContextualButtonGroup mContextualButtonGroup;
     private Configuration mConfiguration;
 
     private NavigationBarInflaterView mNavigationInflaterView;
-    private RecentsComponent mRecentsComponent;
-    private Divider mDivider;
     private RecentsOnboarding mRecentsOnboarding;
     private NotificationPanelView mPanelView;
 
-    private int mRotateBtnStyle = R.style.RotateButtonCCWStart90;
-
     /**
      * Helper that is responsible for showing the right toast when a disallowed activity operation
      * occurred. In pinned mode, we show instructions on how to break out of this mode, whilst in
@@ -279,17 +265,30 @@
                 Context.WINDOW_SERVICE)).getDefaultDisplay();
 
         mVertical = false;
-        mShowMenu = false;
-
-        mShowAccessibilityButton = false;
         mLongClickableAccessibilityButton = false;
 
+        // Set up the context group of buttons
+        mContextualButtonGroup = new ContextualButtonGroup(R.id.menu_container);
+        final ContextualButton menuButton = new ContextualButton(R.id.menu,
+                R.drawable.ic_sysbar_menu);
+        final ContextualButton imeSwitcherButton = new ContextualButton(R.id.ime_switcher,
+                R.drawable.ic_ime_switcher_default);
+        final RotationContextButton rotateSuggestionButton = new RotationContextButton(
+                R.id.rotate_suggestion, R.drawable.ic_sysbar_rotate_button,
+                R.style.RotateButtonCCWStart90);
+        final ContextualButton accessibilityButton =
+                new ContextualButton(R.id.accessibility_button,
+                        R.drawable.ic_sysbar_accessibility_button);
+        mContextualButtonGroup.addButton(menuButton);
+        mContextualButtonGroup.addButton(imeSwitcherButton);
+        mContextualButtonGroup.addButton(rotateSuggestionButton);
+        mContextualButtonGroup.addButton(accessibilityButton);
+
         mOverviewProxyService = Dependency.get(OverviewProxyService.class);
         mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
 
         mConfiguration = new Configuration();
         mConfiguration.updateFrom(context.getResources().getConfiguration());
-        reloadNavIcons();
 
         mScreenPinningNotify = new ScreenPinningNotify(mContext);
         mBarTransitions = new NavigationBarTransitions(this);
@@ -297,14 +296,11 @@
         mButtonDispatchers.put(R.id.back, new ButtonDispatcher(R.id.back));
         mButtonDispatchers.put(R.id.home, new ButtonDispatcher(R.id.home));
         mButtonDispatchers.put(R.id.recent_apps, new ButtonDispatcher(R.id.recent_apps));
-        mButtonDispatchers.put(R.id.menu, new ButtonDispatcher(R.id.menu));
-        mButtonDispatchers.put(R.id.ime_switcher, new ButtonDispatcher(R.id.ime_switcher));
-        mButtonDispatchers.put(R.id.accessibility_button,
-                new ButtonDispatcher(R.id.accessibility_button));
-        mButtonDispatchers.put(R.id.rotate_suggestion,
-                new ButtonDispatcher(R.id.rotate_suggestion));
-        mButtonDispatchers.put(R.id.menu_container,
-                new ButtonDispatcher(R.id.menu_container));
+        mButtonDispatchers.put(R.id.menu, menuButton);
+        mButtonDispatchers.put(R.id.ime_switcher, imeSwitcherButton);
+        mButtonDispatchers.put(R.id.accessibility_button, accessibilityButton);
+        mButtonDispatchers.put(R.id.rotate_suggestion, rotateSuggestionButton);
+        mButtonDispatchers.put(R.id.menu_container, mContextualButtonGroup);
         mDeadZone = new DeadZone(this);
     }
 
@@ -316,14 +312,10 @@
         return mBarTransitions.getLightTransitionsController();
     }
 
-    public void setComponents(RecentsComponent recentsComponent, Divider divider,
-            NotificationPanelView panel) {
-        mRecentsComponent = recentsComponent;
-        mDivider = divider;
+    public void setComponents(NotificationPanelView panel) {
         mPanelView = panel;
         if (mGestureHelper instanceof NavigationBarGestureHelper) {
-            ((NavigationBarGestureHelper) mGestureHelper).setComponents(
-                    recentsComponent, divider, this);
+            ((NavigationBarGestureHelper) mGestureHelper).setComponents(this);
         }
     }
 
@@ -432,10 +424,6 @@
         return mButtonDispatchers.get(R.id.rotate_suggestion);
     }
 
-    public ButtonDispatcher getMenuContainer() {
-        return mButtonDispatchers.get(R.id.menu_container);
-    }
-
     public SparseArray<ButtonDispatcher> getButtonDispatchers() {
         return mButtonDispatchers;
     }
@@ -473,14 +461,7 @@
         }
         if (densityChange || dirChange) {
             mRecentIcon = getDrawable(R.drawable.ic_sysbar_recent);
-            mMenuIcon = getDrawable(R.drawable.ic_sysbar_menu);
-
-            mAccessibilityIcon = getDrawable(R.drawable.ic_sysbar_accessibility_button,
-                    false /* hasShadow */);
-
-            mImeIcon = getDrawable(R.drawable.ic_ime_switcher_default, false /* hasShadow */);
-
-            updateRotateSuggestionButtonStyle(mRotateBtnStyle, false);
+            mContextualButtonGroup.updateIcons();
         }
         if (orientationChange || densityChange || dirChange) {
             mBackIcon = getBackDrawable();
@@ -538,19 +519,11 @@
     }
 
     private KeyButtonDrawable getDrawable(@DrawableRes int icon) {
-        return getDrawable(mContext, icon, true /* hasShadow */);
+        return KeyButtonDrawable.create(mContext, icon, true /* hasShadow */);
     }
 
     private KeyButtonDrawable getDrawable(@DrawableRes int icon, boolean hasShadow) {
-        return getDrawable(mContext, icon, hasShadow);
-    }
-
-    private KeyButtonDrawable getDrawable(Context ctx, @DrawableRes int icon, boolean hasShadow) {
-        final int dualToneDarkTheme = Utils.getThemeAttr(ctx, R.attr.darkIconTheme);
-        final int dualToneLightTheme = Utils.getThemeAttr(ctx, R.attr.lightIconTheme);
-        Context lightContext = new ContextThemeWrapper(ctx, dualToneLightTheme);
-        Context darkContext = new ContextThemeWrapper(ctx, dualToneDarkTheme);
-        return KeyButtonDrawable.create(lightContext, darkContext, icon, hasShadow);
+        return KeyButtonDrawable.create(mContext, icon, hasShadow);
     }
 
     @Override
@@ -609,28 +582,17 @@
         updateRecentsIcon();
 
         // Update IME button visibility, a11y and rotate button always overrides the appearance
-        final boolean showImeButton =
-                !mShowAccessibilityButton &&
-                        !mShowRotateButton &&
-                        ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0);
-        getImeSwitchButton().setVisibility(showImeButton ? View.VISIBLE : View.INVISIBLE);
-        getImeSwitchButton().setImageDrawable(mImeIcon);
-
-        // Update menu button, visibility logic in method
-        setMenuVisibility(mShowMenu, true);
-        getMenuButton().setImageDrawable(mMenuIcon);
-
-        // Update rotate button, visibility altered by a11y button logic
-        getRotateSuggestionButton().setImageDrawable(mRotateSuggestionIcon);
-
-        // Update a11y button, visibility logic in state method
-        setAccessibilityButtonState(mShowAccessibilityButton, mLongClickableAccessibilityButton);
-        getAccessibilityButton().setImageDrawable(mAccessibilityIcon);
+        mContextualButtonGroup.setButtonVisiblity(R.id.ime_switcher,
+                (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0);
 
         mBarTransitions.reapplyDarkIntensity();
 
         boolean disableHome = ((mDisabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
 
+        // TODO(b/113914868): investigation log for disappearing home button
+        Log.i(TAG, "updateNavButtonIcons (b/113914868): home disabled=" + disableHome
+                + " mDisabledFlags=" + mDisabledFlags);
+
         // Always disable recents when alternate car mode UI is active.
         boolean disableRecent = mUseCarModeUi || !isOverviewEnabled();
 
@@ -781,79 +743,29 @@
     }
 
     public void setMenuVisibility(final boolean show) {
-        setMenuVisibility(show, false);
+        mContextualButtonGroup.setButtonVisiblity(R.id.menu, show);
     }
 
-    public void setMenuVisibility(final boolean show, final boolean force) {
-        if (!force && mShowMenu == show) return;
-
-        mShowMenu = show;
-
-        // Only show Menu if IME switcher, rotate and Accessibility buttons are not shown.
-        final boolean shouldShow = mShowMenu &&
-                !mShowAccessibilityButton &&
-                !mShowRotateButton &&
-                ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) == 0);
-
-        getMenuButton().setVisibility(shouldShow ? View.VISIBLE : View.INVISIBLE);
+    public void updateRotateSuggestionButtonStyle(@StyleRes int style) {
+        RotationContextButton button = (RotationContextButton) mContextualButtonGroup
+                .getContextButton(R.id.rotate_suggestion);
+        button.setStyle(style);
+        button.updateIcon();
     }
 
     public void setAccessibilityButtonState(final boolean visible, final boolean longClickable) {
-        mShowAccessibilityButton = visible;
         mLongClickableAccessibilityButton = longClickable;
-        if (visible) {
-            // Accessibility button overrides Menu, IME switcher and rotate buttons.
-            setMenuVisibility(false, true);
-            getImeSwitchButton().setVisibility(View.INVISIBLE);
-            setRotateButtonVisibility(false);
-        }
-
-        getAccessibilityButton().setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
         getAccessibilityButton().setLongClickable(longClickable);
-    }
-
-    public void updateRotateSuggestionButtonStyle(@StyleRes int style, boolean setIcon) {
-        mRotateBtnStyle = style;
-        final Context ctx = getContext();
-
-        // Use the supplied style to set the icon's rotation parameters
-        Context rotateContext = new ContextThemeWrapper(ctx, style);
-
-        // Recreate the icon and set it if needed
-        float previousIntensity = mRotateSuggestionIcon != null
-                ? mRotateSuggestionIcon.getDarkIntensity() : 0;
-        mRotateSuggestionIcon = getDrawable(rotateContext, R.drawable.ic_sysbar_rotate_button,
-                false /* hasShadow */);
-        mRotateSuggestionIcon.setDarkIntensity(previousIntensity);
-
-        if (setIcon) getRotateSuggestionButton().setImageDrawable(mRotateSuggestionIcon);
+        mContextualButtonGroup.setButtonVisiblity(R.id.accessibility_button, visible);
     }
 
     public int setRotateButtonVisibility(boolean visible) {
-        // Never show if a11y is visible
-        final boolean adjVisible = visible && !mShowAccessibilityButton;
-        final int vis = adjVisible ? View.VISIBLE : View.INVISIBLE;
-
-        // No need to do anything if the request matches the current state
-        if (vis == getRotateSuggestionButton().getVisibility()) return vis;
-
-        getRotateSuggestionButton().setVisibility(vis);
-        mShowRotateButton = visible;
-
-        // Stop any active animations if hidden
-        if (!visible && mRotateSuggestionIcon.canAnimate()) {
-            mRotateSuggestionIcon.clearAnimationCallbacks();
-            mRotateSuggestionIcon.resetAnimation();
-        }
-
-        // Hide/restore other button visibility, if necessary
-        updateNavButtonIcons();
-
-        // Return applied visibility
-        return vis;
+        return mContextualButtonGroup.setButtonVisiblity(R.id.rotate_suggestion, visible);
     }
 
-    public boolean isRotateButtonVisible() { return mShowRotateButton; }
+    public boolean isRotateButtonVisible() {
+        return getRotateSuggestionButton().isVisible();
+    }
 
     void hideRecentsOnboarding() {
         mRecentsOnboarding.hide(true);
@@ -886,6 +798,7 @@
 
         DockedStackExistsListener.register(mDockedListener);
         updateRotatedViews();
+        reloadNavIcons();
     }
 
     public void onDarkIntensityChange(float intensity) {
@@ -987,7 +900,6 @@
 
         // force the low profile & disabled states into compliance
         mBarTransitions.init();
-        setMenuVisibility(mShowMenu, true /* force */);
 
         if (DEBUG) {
             Log.d(TAG, "reorient(): rot=" + mCurrentRotation);
@@ -1160,7 +1072,7 @@
     @Override
     public void onPluginDisconnected(NavGesture plugin) {
         NavigationBarGestureHelper defaultHelper = new NavigationBarGestureHelper(getContext());
-        defaultHelper.setComponents(mRecentsComponent, mDivider, this);
+        defaultHelper.setComponents(this);
         if (mGestureHelper != null) {
             mGestureHelper.destroy();
         }
@@ -1193,17 +1105,19 @@
         pw.println(String.format("      disabled=0x%08x vertical=%s menu=%s",
                         mDisabledFlags,
                         mVertical ? "true" : "false",
-                        mShowMenu ? "true" : "false"));
+                        getMenuButton().isVisible() ? "true" : "false"));
 
         dumpButton(pw, "back", getBackButton());
         dumpButton(pw, "home", getHomeButton());
         dumpButton(pw, "rcnt", getRecentsButton());
         dumpButton(pw, "menu", getMenuButton());
+        dumpButton(pw, "rota", getRotateSuggestionButton());
         dumpButton(pw, "a11y", getAccessibilityButton());
 
-        mRecentsOnboarding.dump(pw);
-
         pw.println("    }");
+
+        mContextualButtonGroup.dump(pw);
+        mRecentsOnboarding.dump(pw);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NearestTouchFrame.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NearestTouchFrame.java
index 7b9ed88..1524f80 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NearestTouchFrame.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NearestTouchFrame.java
@@ -95,10 +95,12 @@
     }
 
     private View findNearestChild(MotionEvent event) {
+        if (mClickableChildren.isEmpty()) {
+            return null;
+        }
         return mClickableChildren
                 .stream()
                 .filter(v -> v.isAttachedToWindow())
-                .filter(v -> v.isFocusable())
                 .map(v -> new Pair<>(distance(v, event), v))
                 .min(Comparator.comparingInt(f -> f.first))
                 .get().second;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
index 5fe362f..c08366a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.annotation.NonNull;
 import android.app.Notification;
 import android.os.SystemClock;
 import android.service.notification.StatusBarNotification;
@@ -23,6 +24,9 @@
 import android.util.Log;
 
 import com.android.systemui.Dependency;
+import com.android.systemui.statusbar.AlertingNotificationManager;
+import com.android.systemui.statusbar.AmbientPulseManager;
+import com.android.systemui.statusbar.AmbientPulseManager.OnAmbientChangedListener;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -43,15 +47,18 @@
 /**
  * A class to handle notifications and their corresponding groups.
  */
-public class NotificationGroupManager implements OnHeadsUpChangedListener {
+public class NotificationGroupManager implements OnHeadsUpChangedListener,
+        OnAmbientChangedListener {
 
     private static final String TAG = "NotificationGroupManager";
-    private static final long HEADS_UP_TRANSFER_TIMEOUT = 300;
+    private static final long ALERT_TRANSFER_TIMEOUT = 300;
     private final HashMap<String, NotificationGroup> mGroupMap = new HashMap<>();
     private OnGroupChangeListener mListener;
     private int mBarState = -1;
     private HashMap<String, StatusBarNotification> mIsolatedEntries = new HashMap<>();
     private HeadsUpManager mHeadsUpManager;
+    private AmbientPulseManager mAmbientPulseManager = Dependency.get(AmbientPulseManager.class);
+    private boolean mIsDozing;
     private boolean mIsUpdatingUnchangedGroup;
     private HashMap<String, NotificationData.Entry> mPendingNotifications;
 
@@ -162,40 +169,58 @@
                 mListener.onGroupCreatedFromChildren(group);
             }
         }
-        cleanUpHeadsUpStatesOnAdd(group, false /* addIsPending */);
+        cleanUpAlertStatesOnAdd(group, false /* addIsPending */);
     }
 
     public void onPendingEntryAdded(NotificationData.Entry shadeEntry) {
         String groupKey = getGroupKey(shadeEntry.notification);
         NotificationGroup group = mGroupMap.get(groupKey);
         if (group != null) {
-            cleanUpHeadsUpStatesOnAdd(group, true /* addIsPending */);
+            cleanUpAlertStatesOnAdd(group, true /* addIsPending */);
         }
     }
 
     /**
-     * Clean up the heads up states when a new child was added.
+     * Set whether or not the device is dozing.  This allows the group manager to reset some
+     * specific alert state logic based off when the state changes.
+     * @param isDozing if the device is dozing.
+     */
+    public void setDozing(boolean isDozing) {
+        if (mIsDozing != isDozing) {
+            for (NotificationGroup group : mGroupMap.values()) {
+                group.lastAlertTransfer = 0;
+                group.alertSummaryOnNextAddition = false;
+            }
+        }
+        mIsDozing = isDozing;
+    }
+
+    /**
+     * Clean up the alert states when a new child was added.
      * @param group The group where a view was added or will be added.
      * @param addIsPending True if is the addition still pending or false has it already been added.
      */
-    private void cleanUpHeadsUpStatesOnAdd(NotificationGroup group, boolean addIsPending) {
-        if (!addIsPending && group.hunSummaryOnNextAddition) {
-            if (!mHeadsUpManager.contains(group.summary.key)) {
-                mHeadsUpManager.showNotification(group.summary);
+    private void cleanUpAlertStatesOnAdd(NotificationGroup group, boolean addIsPending) {
+
+        AlertingNotificationManager alertManager =
+                mIsDozing ? mAmbientPulseManager : mHeadsUpManager;
+        if (!addIsPending && group.alertSummaryOnNextAddition) {
+            if (!alertManager.isAlerting(group.summary.key)) {
+                alertManager.showNotification(group.summary);
             }
-            group.hunSummaryOnNextAddition = false;
+            group.alertSummaryOnNextAddition = false;
         }
         // Because notification groups are not delivered as a whole unit, it may happen that a
         // group child gets added quite a bit after the summary got posted. Our guidance is, that
         // apps should always post the group summary as well and we'll hide it for them if the child
-        // is the only child in a group. Because of this, we also have to transfer heads up to the
-        // child, otherwise the invisible summary would be heads-upped.
+        // is the only child in a group. Because of this, we also have to transfer alert to the
+        // child, otherwise the invisible summary would be alerted.
         // This transfer to the child is not always correct in case the app has just posted another
         // child in addition to the existing one, but it hasn't arrived in systemUI yet. In such
-        // a scenario we would transfer the heads up to the old child and the wrong notification
-        // would be heads-upped. In oder to avoid this, we'll recover from this issue and hun the
+        // a scenario we would transfer the alert to the old child and the wrong notification
+        // would be alerted. In order to avoid this, we'll recover from this issue and alert the
         // summary again instead of the old child if it's within a certain timeout.
-        if (SystemClock.elapsedRealtime() - group.lastHeadsUpTransfer < HEADS_UP_TRANSFER_TIMEOUT) {
+        if (SystemClock.elapsedRealtime() - group.lastAlertTransfer < ALERT_TRANSFER_TIMEOUT) {
             if (!onlySummaryAlerts(group.summary)) {
                 return;
             }
@@ -215,26 +240,24 @@
             int size = children.size();
             for (int i = 0; i < size; i++) {
                 NotificationData.Entry entry = children.get(i);
-                if (onlySummaryAlerts(entry) && entry.row.isHeadsUp()) {
+                if (onlySummaryAlerts(entry) && alertManager.isAlerting(entry.key)) {
                     releasedChild = true;
-                    mHeadsUpManager.removeNotification(
-                            entry.key, true /* releaseImmediately */);
+                    alertManager.removeNotification(entry.key, true /* releaseImmediately */);
                 }
             }
             if (isolatedChild != null && onlySummaryAlerts(isolatedChild)
-                    && isolatedChild.row.isHeadsUp()) {
+                    && alertManager.isAlerting(isolatedChild.key)) {
                 releasedChild = true;
-                mHeadsUpManager.removeNotification(
-                        isolatedChild.key, true /* releaseImmediately */);
+                alertManager.removeNotification(isolatedChild.key, true /* releaseImmediately */);
             }
-            if (releasedChild && !mHeadsUpManager.contains(group.summary.key)) {
+            if (releasedChild && !alertManager.isAlerting(group.summary.key)) {
                 boolean notifyImmediately = (numChildren - numPendingChildren) > 1;
                 if (notifyImmediately) {
-                    mHeadsUpManager.showNotification(group.summary);
+                    alertManager.showNotification(group.summary);
                 } else {
-                    group.hunSummaryOnNextAddition = true;
+                    group.alertSummaryOnNextAddition = true;
                 }
-                group.lastHeadsUpTransfer = 0;
+                group.lastAlertTransfer = 0;
             }
         }
     }
@@ -264,8 +287,8 @@
     }
 
     private void onEntryBecomingChild(NotificationData.Entry entry) {
-        if (entry.row.isHeadsUp()) {
-            onHeadsUpStateChanged(entry, true);
+        if (shouldIsolate(entry)) {
+            isolateNotification(entry);
         }
     }
 
@@ -281,7 +304,11 @@
                         && hasIsolatedChildren(group)));
         if (prevSuppressed != group.suppressed) {
             if (group.suppressed) {
-                handleSuppressedSummaryHeadsUpped(group.summary);
+                if (mHeadsUpManager.isAlerting(group.summary.key)) {
+                    handleSuppressedSummaryAlerted(group.summary, mHeadsUpManager);
+                } else if (mAmbientPulseManager.isAlerting(group.summary.key)) {
+                    handleSuppressedSummaryAlerted(group.summary, mAmbientPulseManager);
+                }
             }
             if (!mIsUpdatingUnchangedGroup && mListener != null) {
                 mListener.onGroupsChanged();
@@ -415,10 +442,10 @@
             return false;
         }
         NotificationGroup group = mGroupMap.get(getGroupKey(sbn));
-        if (group == null) {
+        if (group == null || group.summary == null) {
             return false;
         }
-        return !group.children.isEmpty();
+        return !group.children.isEmpty() && Objects.equals(group.summary.notification, sbn);
     }
 
     /**
@@ -495,54 +522,56 @@
     }
 
     @Override
+    public void onAmbientStateChanged(NotificationData.Entry entry, boolean isAmbient) {
+        onAlertStateChanged(entry, isAmbient, mAmbientPulseManager);
+    }
+
+    @Override
     public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {
+        onAlertStateChanged(entry, isHeadsUp, mHeadsUpManager);
+    }
+
+    private void onAlertStateChanged(NotificationData.Entry entry, boolean isAlerting,
+            AlertingNotificationManager alertManager) {
         final StatusBarNotification sbn = entry.notification;
-        if (entry.row.isHeadsUp()) {
-            if (shouldIsolate(sbn)) {
-                // We will be isolated now, so lets update the groups
-                onEntryRemovedInternal(entry, entry.notification);
-
-                mIsolatedEntries.put(sbn.getKey(), sbn);
-
-                onEntryAdded(entry);
-                // We also need to update the suppression of the old group, because this call comes
-                // even before the groupManager knows about the notification at all.
-                // When the notification gets added afterwards it is already isolated and therefore
-                // it doesn't lead to an update.
-                updateSuppression(mGroupMap.get(entry.notification.getGroupKey()));
-                mListener.onGroupsChanged();
-            } else {
-                handleSuppressedSummaryHeadsUpped(entry);
+        if (isAlerting) {
+            if (shouldIsolate(entry)) {
+                isolateNotification(entry);
+            } else if (sbn.getNotification().isGroupSummary()
+                    && isGroupSuppressed(sbn.getGroupKey())){
+                handleSuppressedSummaryAlerted(entry, alertManager);
             }
         } else {
-            if (mIsolatedEntries.containsKey(sbn.getKey())) {
-                // not isolated anymore, we need to update the groups
-                onEntryRemovedInternal(entry, entry.notification);
-                mIsolatedEntries.remove(sbn.getKey());
-                onEntryAdded(entry);
-                mListener.onGroupsChanged();
-            }
+            stopIsolatingNotification(entry);
         }
     }
 
-    private void handleSuppressedSummaryHeadsUpped(NotificationData.Entry entry) {
-        StatusBarNotification sbn = entry.notification;
+    /**
+     * Handles the scenario where a summary that has been suppressed is alerted.  A suppressed
+     * summary should for all intents and purposes be invisible to the user and as a result should
+     * not alert.  When this is the case, it is our responsibility to pass the alert to the
+     * appropriate child which will be the representative notification alerting for the group.
+     * @param summary the summary that is suppressed and alerting
+     * @param alertManager the alert manager that manages the alerting summary
+     */
+    private void handleSuppressedSummaryAlerted(@NonNull NotificationData.Entry summary,
+            @NonNull AlertingNotificationManager alertManager) {
+        StatusBarNotification sbn = summary.notification;
         if (!isGroupSuppressed(sbn.getGroupKey())
                 || !sbn.getNotification().isGroupSummary()
-                || !entry.row.isHeadsUp()) {
+                || !alertManager.isAlerting(sbn.getKey())) {
             return;
         }
 
-        // The parent of a suppressed group got huned, lets hun the child!
+        // The parent of a suppressed group got alerted, lets alert the child!
         NotificationGroup notificationGroup = mGroupMap.get(sbn.getGroupKey());
 
-        if (pendingInflationsWillAddChildren(notificationGroup)) {
-            // New children will actually be added to this group, let's not transfer the heads
-            // up
-            return;
-        }
-
         if (notificationGroup != null) {
+            if (pendingInflationsWillAddChildren(notificationGroup)) {
+                // New children will actually be added to this group, let's not transfer the alert.
+                return;
+            }
+
             Iterator<NotificationData.Entry> iterator
                     = notificationGroup.children.values().iterator();
             NotificationData.Entry child = iterator.hasNext() ? iterator.next() : null;
@@ -551,20 +580,35 @@
             }
             if (child != null) {
                 if (child.row.keepInParent() || child.row.isRemoved() || child.row.isDismissed()) {
-                    // the notification is actually already removed, no need to do heads-up on it.
+                    // the notification is actually already removed, no need to do alert on it.
                     return;
                 }
-                if (mHeadsUpManager.contains(child.key)) {
-                    mHeadsUpManager.updateNotification(child.key, true /* alert */);
-                } else {
-                    if (onlySummaryAlerts(entry)) {
-                        notificationGroup.lastHeadsUpTransfer = SystemClock.elapsedRealtime();
-                    }
-                    mHeadsUpManager.showNotification(child);
-                }
+                transferAlertStateToChild(summary, child, alertManager);
             }
         }
-        mHeadsUpManager.removeNotification(entry.key, true /* releaseImmediately */);
+    }
+
+    /**
+     * Transfers the alert state from a given summary notification to the specified child.  The
+     * result is the child will now alert while the summary does not.
+     *
+     * @param summary the currently alerting summary notification
+     * @param child the child that should receive the alert
+     * @param alertManager the manager for the alert
+     */
+    private void transferAlertStateToChild(@NonNull NotificationData.Entry summary,
+            @NonNull NotificationData.Entry child,
+            @NonNull AlertingNotificationManager alertManager) {
+        NotificationGroup notificationGroup = mGroupMap.get(summary.notification.getGroupKey());
+        if (alertManager.isAlerting(child.key)) {
+            alertManager.updateNotification(child.key, true /* alert */);
+        } else {
+            if (onlySummaryAlerts(summary)) {
+                notificationGroup.lastAlertTransfer = SystemClock.elapsedRealtime();
+            }
+            alertManager.showNotification(child);
+        }
+        alertManager.removeNotification(summary.key, true /* releaseImmediately */);
     }
 
     private boolean onlySummaryAlerts(NotificationData.Entry entry) {
@@ -596,13 +640,69 @@
         return false;
     }
 
-    private boolean shouldIsolate(StatusBarNotification sbn) {
+    /**
+     * Whether a notification that is normally part of a group should be temporarily isolated from
+     * the group and put in their own group visually.  This generally happens when the notification
+     * is alerting.
+     *
+     * @param entry the notification to check
+     * @return true if the entry should be isolated
+     */
+
+    private boolean shouldIsolate(NotificationData.Entry entry) {
+        StatusBarNotification sbn = entry.notification;
         NotificationGroup notificationGroup = mGroupMap.get(sbn.getGroupKey());
-        return (sbn.isGroup() && !sbn.getNotification().isGroupSummary())
-                && (sbn.getNotification().fullScreenIntent != null
-                        || notificationGroup == null
-                        || !notificationGroup.expanded
-                        || isGroupNotFullyVisible(notificationGroup));
+        if (!sbn.isGroup() || sbn.getNotification().isGroupSummary()) {
+            return false;
+        }
+        if (!mIsDozing && !mHeadsUpManager.isAlerting(entry.key)) {
+            return false;
+        }
+        if (mIsDozing && !mAmbientPulseManager.isAlerting(entry.key)) {
+            return false;
+        }
+        return (sbn.getNotification().fullScreenIntent != null
+                    || notificationGroup == null
+                    || !notificationGroup.expanded
+                    || isGroupNotFullyVisible(notificationGroup));
+    }
+
+    /**
+     * Isolate a notification from its group so that it visually shows as its own group.
+     *
+     * @param entry the notification to isolate
+     */
+    private void isolateNotification(NotificationData.Entry entry) {
+        StatusBarNotification sbn = entry.notification;
+
+        // We will be isolated now, so lets update the groups
+        onEntryRemovedInternal(entry, entry.notification);
+
+        mIsolatedEntries.put(sbn.getKey(), sbn);
+
+        onEntryAdded(entry);
+        // We also need to update the suppression of the old group, because this call comes
+        // even before the groupManager knows about the notification at all.
+        // When the notification gets added afterwards it is already isolated and therefore
+        // it doesn't lead to an update.
+        updateSuppression(mGroupMap.get(entry.notification.getGroupKey()));
+        mListener.onGroupsChanged();
+    }
+
+    /**
+     * Stop isolating a notification and re-group it with its original logical group.
+     *
+     * @param entry the notification to un-isolate
+     */
+    private void stopIsolatingNotification(NotificationData.Entry entry) {
+        StatusBarNotification sbn = entry.notification;
+        if (mIsolatedEntries.containsKey(sbn.getKey())) {
+            // not isolated anymore, we need to update the groups
+            onEntryRemovedInternal(entry, entry.notification);
+            mIsolatedEntries.remove(sbn.getKey());
+            onEntryAdded(entry);
+            mListener.onGroupsChanged();
+        }
     }
 
     private boolean isGroupNotFullyVisible(NotificationGroup notificationGroup) {
@@ -641,11 +741,11 @@
          */
         public boolean suppressed;
         /**
-         * The time when the last heads transfer from group to child happened, while the summary
-         * has the flags to heads up on its own.
+         * The time when the last alert transfer from group to child happened, while the summary
+         * has the flags to alert up on its own.
          */
-        public long lastHeadsUpTransfer;
-        public boolean hunSummaryOnNextAddition;
+        public long lastAlertTransfer;
+        public boolean alertSummaryOnNextAddition;
 
         @Override
         public String toString() {
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 e5e5d40..3a4c218 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -63,6 +63,7 @@
 import com.android.systemui.fragments.FragmentHostManager;
 import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
 import com.android.systemui.plugins.qs.QS;
+import com.android.systemui.qs.QSFragment;
 import com.android.systemui.statusbar.FlingAnimationUtils;
 import com.android.systemui.statusbar.GestureRecorder;
 import com.android.systemui.statusbar.KeyguardAffordanceView;
@@ -455,6 +456,10 @@
         initBottomArea();
         setDarkAmount(mLinearDarkAmount, mInterpolatedDarkAmount);
 
+        if (mKeyguardStatusBar != null) {
+            mKeyguardStatusBar.onThemeChanged();
+        }
+
         setKeyguardStatusViewVisibility(mBarState, false, false);
         setKeyguardBottomAreaVisibility(mBarState, false);
     }
@@ -1836,10 +1841,10 @@
             return;
         }
         float alphaQsExpansion = 1 - Math.min(1, getQsExpansionFraction() * 2);
-        mKeyguardStatusBar.setAlpha(Math.min(getKeyguardContentsAlpha(), alphaQsExpansion)
-                * mKeyguardStatusBarAnimateAlpha);
-        mKeyguardStatusBar.setVisibility(mKeyguardStatusBar.getAlpha() != 0f
-                && !mDozing ? VISIBLE : INVISIBLE);
+        float newAlpha = Math.min(getKeyguardContentsAlpha(), alphaQsExpansion)
+                * mKeyguardStatusBarAnimateAlpha;
+        mKeyguardStatusBar.setAlpha(newAlpha);
+        mKeyguardStatusBar.setVisibility(newAlpha != 0f ? VISIBLE : INVISIBLE);
     }
 
     private void updateKeyguardBottomAreaAlpha() {
@@ -2347,16 +2352,7 @@
     }
 
     private void updateDozingVisibilities(boolean animate) {
-        if (mDozing) {
-            mKeyguardStatusBar.setVisibility(View.INVISIBLE);
-            mKeyguardBottomArea.setDozing(mDozing, animate);
-        } else {
-            mKeyguardStatusBar.setVisibility(View.VISIBLE);
-            mKeyguardBottomArea.setDozing(mDozing, animate);
-            if (animate) {
-                animateKeyguardStatusBarIn(DOZE_ANIMATION_DURATION);
-            }
-        }
+        mKeyguardBottomArea.setDozing(mDozing, animate);
     }
 
     @Override
@@ -2749,6 +2745,9 @@
                         }
                     });
             mNotificationStackScroller.setQsContainer((ViewGroup) mQs.getView());
+            if (mQs instanceof QSFragment) {
+                mKeyguardStatusBar.setQSPanel(((QSFragment) mQs).getQsPanel());
+            }
             updateQsExpansion();
         }
 
@@ -2811,6 +2810,7 @@
     private void setDarkAmount(float linearAmount, float amount) {
         mInterpolatedDarkAmount = amount;
         mLinearDarkAmount = linearAmount;
+        mKeyguardStatusBar.setDarkAmount(mInterpolatedDarkAmount);
         mKeyguardStatusView.setDarkAmount(mInterpolatedDarkAmount);
         mKeyguardBottomArea.setDarkAmount(mInterpolatedDarkAmount);
         positionClockAndNotifications();
@@ -2837,6 +2837,7 @@
     }
 
     public void dozeTimeTick() {
+        mKeyguardStatusBar.dozeTimeTick();
         mKeyguardStatusView.dozeTimeTick();
         mKeyguardBottomArea.dozeTimeTick();
         if (mInterpolatedDarkAmount > 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index a900c14..553165b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -67,8 +67,8 @@
 import com.android.systemui.UiOffloadThread;
 import com.android.systemui.qs.tiles.DndTile;
 import com.android.systemui.qs.tiles.RotationLockTile;
-import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.CommandQueue.Callbacks;
 import com.android.systemui.statusbar.policy.BluetoothController;
@@ -595,16 +595,29 @@
         extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
                 mContext.getString(R.string.instant_apps));
         mCurrentNotifs.add(new Pair<>(pkg, userId));
-        String message = mContext.getString(R.string.instant_apps_message);
+
+        String helpUrl = mContext.getString(R.string.instant_apps_help_url);
+        boolean hasHelpUrl = !helpUrl.isEmpty();
+        String message = mContext.getString(hasHelpUrl
+                ? R.string.instant_apps_message_with_help
+                : R.string.instant_apps_message);
+
         UserHandle user = UserHandle.of(userId);
         PendingIntent appInfoAction = PendingIntent.getActivityAsUser(mContext, 0,
                 new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                         .setData(Uri.fromParts("package", pkg, null)), 0, null, user);
         Action action = new Notification.Action.Builder(null, mContext.getString(R.string.app_info),
                 appInfoAction).build();
+        PendingIntent helpCenterIntent = hasHelpUrl
+                ? PendingIntent.getActivityAsUser(mContext, 0,
+                new Intent(Intent.ACTION_VIEW).setData(Uri.parse(
+                        helpUrl)),
+                0, null, user)
+                : null;
 
         Intent browserIntent = getTaskIntent(taskId, userId);
-        Notification.Builder builder = new Notification.Builder(mContext, NotificationChannels.GENERAL);
+        Notification.Builder builder = new Notification.Builder(mContext,
+                NotificationChannels.GENERAL);
         if (browserIntent != null && browserIntent.isWebIntent()) {
             // Make sure that this doesn't resolve back to an instant app
             browserIntent.setComponent(null)
@@ -632,7 +645,8 @@
 
             PendingIntent webPendingIntent = PendingIntent.getActivityAsUser(mContext, 0,
                     goToWebIntent, 0, null, user);
-            Action webAction = new Notification.Action.Builder(null, mContext.getString(R.string.go_to_web),
+            Action webAction = new Notification.Action.Builder(null,
+                    mContext.getString(R.string.go_to_web),
                     webPendingIntent).build();
             builder.addAction(webAction);
         }
@@ -640,13 +654,15 @@
         noMan.notifyAsUser(pkg, SystemMessage.NOTE_INSTANT_APPS, builder
                         .addExtras(extras)
                         .addAction(action)
-                        .setContentIntent(appInfoAction)
+                        .setContentIntent(helpCenterIntent)
                         .setColor(mContext.getColor(R.color.instant_apps_color))
-                        .setContentTitle(appInfo.loadLabel(mContext.getPackageManager()))
+                        .setContentTitle(mContext.getString(R.string.instant_apps_title,
+                                appInfo.loadLabel(mContext.getPackageManager())))
                         .setLargeIcon(Icon.createWithResource(pkg, appInfo.icon))
                         .setSmallIcon(Icon.createWithResource(mContext.getPackageName(),
                                 R.drawable.instant_icon))
                         .setContentText(message)
+                        .setStyle(new Notification.BigTextStyle().bigText(message))
                         .setOngoing(true)
                         .build(),
                 new UserHandle(userId));
@@ -781,7 +797,7 @@
         mIconController.setIconVisibility(mSlotDataSaver, isDataSaving);
     }
 
-    private final SysUiTaskStackChangeListener mTaskListener = new SysUiTaskStackChangeListener() {
+    private final TaskStackChangeListener mTaskListener = new TaskStackChangeListener() {
         @Override
         public void onTaskStackChanged() {
             // Listen for changes to stacks and then check which instant apps are foreground.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
index bd4d790..30e6afa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -77,6 +77,8 @@
     /** Experiment to swipe home button left to execute a back key press */
     private static final String PULL_HOME_GO_BACK_PROP = "persist.quickstepcontroller.homegoesback";
     private static final String HIDE_BACK_BUTTON_PROP = "persist.quickstepcontroller.hideback";
+    private static final String BACK_AFTER_END_PROP
+            = "persist.quickstepcontroller.homegoesbackwhenend";
     private static final long BACK_BUTTON_FADE_OUT_ALPHA = 60;
     private static final long BACK_BUTTON_FADE_IN_ALPHA = 150;
     private static final long BACK_GESTURE_POLL_TIMEOUT = 1000;
@@ -84,9 +86,6 @@
     /** When the home-swipe-back gesture is disallowed, make it harder to pull */
     private static final float DISALLOW_GESTURE_DAMPING_FACTOR = 0.16f;
 
-    /** When dragging the home button too far during back gesture, make it harder to pull */
-    private static final float EXCEED_DRAG_HOME_DAMPING_FACTOR = 0.33f;
-
     private NavigationBarView mNavigationBarView;
 
     private boolean mQuickScrubActive;
@@ -361,7 +360,7 @@
                         // Once the user drags the home button past a certain limit, the distance
                         // will lessen as the home button dampens showing that it was pulled too far
                         float distanceAfterDragLimit = (Math.abs(diff) - mHomeBackGestureDragLimit)
-                                * EXCEED_DRAG_HOME_DAMPING_FACTOR;
+                                * DISALLOW_GESTURE_DAMPING_FACTOR;
                         diff = (int)(distanceAfterDragLimit + mHomeBackGestureDragLimit);
                         if (mDragPositive) {
                             diff *= -1;
@@ -580,15 +579,21 @@
         if (!mBackGestureActive) {
             mBackGestureActive = true;
             mNavigationBarView.getHomeButton().abortCurrentGesture();
+            final boolean runBackMidGesture
+                    = !SystemProperties.getBoolean(BACK_AFTER_END_PROP, false);
             if (mCanPerformBack) {
                 if (!shouldhideBackButton()) {
                     mNavigationBarView.getBackButton().setAlpha(0 /* alpha */, true /* animate */,
                             BACK_BUTTON_FADE_OUT_ALPHA);
                 }
-                performBack();
+                if (runBackMidGesture) {
+                    performBack();
+                }
             }
             mHandler.removeCallbacks(mExecuteBackRunnable);
-            mHandler.postDelayed(mExecuteBackRunnable, BACK_GESTURE_POLL_TIMEOUT);
+            if (runBackMidGesture) {
+                mHandler.postDelayed(mExecuteBackRunnable, BACK_GESTURE_POLL_TIMEOUT);
+            }
         }
     }
 
@@ -609,6 +614,9 @@
                 mNavigationBarView.getBackButton().setAlpha(
                         mOverviewEventSender.getBackButtonAlpha(), true /* animate */);
             }
+            if (SystemProperties.getBoolean(BACK_AFTER_END_PROP, false)) {
+                performBack();
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java
new file mode 100644
index 0000000..15e189c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.annotation.DrawableRes;
+import android.annotation.IdRes;
+import android.annotation.NonNull;
+import android.annotation.StyleRes;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.view.ContextThemeWrapper;
+import android.view.View;
+import com.android.systemui.statusbar.policy.KeyButtonDrawable;
+import com.android.systemui.util.Utils;
+
+public class RotationContextButton extends ContextualButton {
+
+    private @StyleRes int mStyleRes;
+
+    public RotationContextButton(@IdRes int buttonResId, @DrawableRes int iconResId,
+            @StyleRes int style) {
+        super(buttonResId, iconResId);
+        mStyleRes = style;
+    }
+
+    public void setStyle(@StyleRes int styleRes) {
+        mStyleRes = styleRes;
+    }
+
+    @Override
+    public void setVisibility(int visibility) {
+        super.setVisibility(visibility);
+
+        // Start the rotation animation once it becomes visible
+        final KeyButtonDrawable currentDrawable = getImageDrawable();
+        if (visibility == View.VISIBLE && currentDrawable != null) {
+            currentDrawable.resetAnimation();
+            currentDrawable.startAnimation();
+        }
+    }
+
+    @Override
+    protected KeyButtonDrawable getNewDrawable() {
+        Context context = new ContextThemeWrapper(getContext().getApplicationContext(), mStyleRes);
+        return KeyButtonDrawable.create(context, mIconResId, false /* shadow */);
+    }
+}
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 7ec4db2..226b645 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -102,6 +102,8 @@
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.provider.Settings;
+import android.service.dreams.DreamService;
+import android.service.dreams.IDreamManager;
 import android.service.notification.StatusBarNotification;
 import android.service.vr.IVrManager;
 import android.service.vr.IVrStateCallbacks;
@@ -154,6 +156,7 @@
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
+import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.SystemUI;
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.UiOffloadThread;
@@ -179,14 +182,11 @@
 import com.android.systemui.qs.car.CarQSFragment;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.ScreenPinningRequest;
-import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent;
-import com.android.systemui.recents.events.activity.UndockingTaskEvent;
-import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.shared.system.WindowManagerWrapper;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.stackdivider.WindowManagerProxy;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.AmbientPulseManager;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.AppOpsListener;
 import com.android.systemui.statusbar.BackDropView;
@@ -254,7 +254,8 @@
         ActivityStarter, OnUnlockMethodChangedListener,
         OnHeadsUpChangedListener, CommandQueue.Callbacks, ZenModeController.Callback,
         ColorExtractor.OnColorsChangedListener, ConfigurationListener, NotificationPresenter,
-        StatusBarStateController.StateListener {
+        StatusBarStateController.StateListener,  AmbientPulseManager.OnAmbientChangedListener,
+        ActivityLaunchAnimator.Callback {
     public static final boolean MULTIUSER_DEBUG = false;
 
     public static final boolean ENABLE_CHILD_NOTIFICATIONS
@@ -380,8 +381,6 @@
     // settings
     private QSPanel mQSPanel;
 
-    // top bar
-    private KeyguardStatusBarView mKeyguardStatusBar;
     KeyguardIndicationController mKeyguardIndicationController;
 
     // RemoteInputView to be activated after unlock
@@ -632,9 +631,11 @@
 
         mColorExtractor = Dependency.get(SysuiColorExtractor.class);
         mColorExtractor.addOnColorsChangedListener(this);
-        mStatusBarStateController.addListener(this);
+        mStatusBarStateController.addListener(this, StatusBarStateController.RANK_STATUS_BAR);
 
         mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+        mDreamManager = IDreamManager.Stub.asInterface(
+                ServiceManager.checkService(DreamService.DREAM_SERVICE));
 
         mDisplay = mWindowManager.getDefaultDisplay();
         updateDisplaySize();
@@ -732,10 +733,12 @@
 
         IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService(
                 Context.VR_SERVICE));
-        try {
-            vrManager.registerListener(mVrStateCallbacks);
-        } catch (RemoteException e) {
-            Slog.e(TAG, "Failed to register VR mode state listener: " + e);
+        if (vrManager != null) {
+            try {
+                vrManager.registerListener(mVrStateCallbacks);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to register VR mode state listener: " + e);
+            }
         }
 
         IWallpaperManager wallpaperManager = IWallpaperManager.Stub.asInterface(
@@ -802,7 +805,6 @@
         mAboveShelfObserver = new AboveShelfObserver(mStackScroller);
         mAboveShelfObserver.setListener(mStatusBarWindow.findViewById(
                 R.id.notification_container_parent));
-        mKeyguardStatusBar = mStatusBarWindow.findViewById(R.id.keyguard_header);
 
         mNotificationIconAreaController = SystemUIFactory.getInstance()
                 .createNotificationIconAreaController(context, this);
@@ -863,6 +865,8 @@
         mHeadsUpManager.addListener(mNotificationPanel);
         mHeadsUpManager.addListener(mGroupManager);
         mHeadsUpManager.addListener(mVisualStabilityManager);
+        mAmbientPulseManager.addListener(this);
+        mAmbientPulseManager.addListener(mGroupManager);
         mNotificationPanel.setHeadsUpManager(mHeadsUpManager);
         mGroupManager.setHeadsUpManager(mHeadsUpManager);
         putComponent(HeadsUpManager.class, mHeadsUpManager);
@@ -975,7 +979,6 @@
                     ((QSFragment) qs).setHost(qsh);
                     mQSPanel = ((QSFragment) qs).getQsPanel();
                     mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
-                    mKeyguardStatusBar.setQSPanel(mQSPanel);
                 }
             });
         }
@@ -1113,8 +1116,6 @@
 
     @Override
     public void onThemeChanged() {
-        // The status bar on the keyguard is a special layout.
-        if (mKeyguardStatusBar != null) mKeyguardStatusBar.onThemeChanged();
         // Recreate Indication controller because internal references changed
         mKeyguardIndicationController =
                 SystemUIFactory.getInstance().createKeyguardIndicationController(mContext,
@@ -1142,11 +1143,6 @@
 
     @Override
     public void onUiModeChanged() {
-        // UiMode will change the style was already evaluated.
-        // We need to force the re-evaluation to make sure that all parents
-        // are up to date and new attrs will be rettrieved.
-        mContext.getTheme().applyStyle(mContext.getThemeResId(), true);
-
         if (mBrightnessMirrorController != null) {
             mBrightnessMirrorController.onUiModeChanged();
         }
@@ -1154,7 +1150,8 @@
 
     protected void createUserSwitcher() {
         mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext,
-                mStatusBarWindow.findViewById(R.id.keyguard_user_switcher), mKeyguardStatusBar,
+                mStatusBarWindow.findViewById(R.id.keyguard_user_switcher),
+                mStatusBarWindow.findViewById(R.id.keyguard_header),
                 mNotificationPanel);
     }
 
@@ -1171,6 +1168,8 @@
                 mScrimController, this, UnlockMethodCache.getInstance(mContext));
         mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
                 getBouncerContainer(), mNotificationPanel, mBiometricUnlockController);
+        //TODO: Can we put the keyguard view manager in Dependency?
+        mLockscreenUserManager.setKeyguardViewManager(mStatusBarKeyguardViewManager);
         mKeyguardIndicationController
                 .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
         mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
@@ -1216,17 +1215,18 @@
             int createMode = navbarPos == NAV_BAR_POS_LEFT
                     ? SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT
                     : SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
-            return mRecents.splitPrimaryTask(NavigationBarGestureHelper.DRAG_MODE_NONE, createMode,
-                    null, metricsDockAction);
+            return mRecents.splitPrimaryTask(createMode, null, metricsDockAction);
         } else {
             Divider divider = getComponent(Divider.class);
-            if (divider != null && divider.isMinimized() && !divider.isHomeStackResizable()) {
-                // Undocking from the minimized state is not supported
-                return false;
-            } else {
-                EventBus.getDefault().send(new UndockingTaskEvent());
-                if (metricsUndockAction != -1) {
-                    mMetricsLogger.action(metricsUndockAction);
+            if (divider != null) {
+                if (divider.isMinimized() && !divider.isHomeStackResizable()) {
+                    // Undocking from the minimized state is not supported
+                    return false;
+                } else {
+                    divider.onUndockingTask();
+                    if (metricsUndockAction != -1) {
+                        mMetricsLogger.action(metricsUndockAction);
+                    }
                 }
             }
         }
@@ -1236,7 +1236,7 @@
     @Override
     public void onPerformRemoveNotification(StatusBarNotification n) {
         if (mNotificationPanel.hasPulsingNotifications() &&
-                    !mHeadsUpManager.hasNotifications()) {
+                    !mAmbientPulseManager.hasNotifications()) {
             // We were showing a pulse for a notification, but no notifications are pulsing anymore.
             // Finish the pulse.
             mDozeScrimController.pulseOutNow();
@@ -1700,8 +1700,12 @@
     }
 
     @Override
-    public boolean shouldPeek(Entry entry, StatusBarNotification sbn) {
-        if (mIsOccluded && !isDozing()) {
+    public boolean canHeadsUp(Entry entry, StatusBarNotification sbn) {
+        if (isDozing()) {
+            return false;
+        }
+
+        if (mIsOccluded) {
             boolean devicePublic = mLockscreenUserManager.
                     isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId());
             boolean userPublic = devicePublic
@@ -1714,17 +1718,14 @@
 
         if (!panelsEnabled()) {
             if (DEBUG) {
-                Log.d(TAG, "No peeking: disabled panel : " + sbn.getKey());
+                Log.d(TAG, "No heads up: disabled panel : " + sbn.getKey());
             }
             return false;
         }
 
         if (sbn.getNotification().fullScreenIntent != null) {
             if (mAccessibilityManager.isTouchExplorationEnabled()) {
-                if (DEBUG) Log.d(TAG, "No peeking: accessible fullscreen: " + sbn.getKey());
-                return false;
-            } else if (isDozing()) {
-                // We never want heads up when we are dozing.
+                if (DEBUG) Log.d(TAG, "No heads up: accessible fullscreen: " + sbn.getKey());
                 return false;
             } else {
                 // we only allow head-up on the lockscreen if it doesn't have a fullscreen intent
@@ -1800,9 +1801,16 @@
     @Override
     public void onHeadsUpStateChanged(Entry entry, boolean isHeadsUp) {
         mEntryManager.updateNotificationRanking(null /* rankingMap */);
+    }
 
-        if (isHeadsUp) {
-            mDozeServiceHost.fireNotificationHeadsUp();
+    @Override
+    public void onAmbientStateChanged(Entry entry, boolean isAmbient) {
+        mEntryManager.updateNotificationRanking(null);
+        if (isAmbient) {
+            mDozeServiceHost.fireNotificationPulse();
+        } else if (!mAmbientPulseManager.hasNotifications()) {
+            // There are no longer any notifications to show.  We should end the pulse now.
+            mDozeScrimController.pulseOutNow();
         }
     }
 
@@ -1903,6 +1911,7 @@
         }
     }
 
+    @Override
     public void onLaunchAnimationCancelled() {
         if (!isCollapsing()) {
             onClosingFinished();
@@ -1913,6 +1922,31 @@
         return mHeadsUpAppearanceController.shouldBeVisible();
     }
 
+    @Override
+    public void onExpandAnimationFinished(boolean launchIsFullScreen) {
+        if (!isCollapsing()) {
+            onClosingFinished();
+        }
+        if (launchIsFullScreen) {
+            instantCollapseNotificationPanel();
+        }
+    }
+
+    @Override
+    public void onExpandAnimationTimedOut() {
+        if (isPresenterFullyCollapsed() && !isCollapsing()
+                && !mActivityLaunchAnimator.isLaunchForActivity()) {
+            onClosingFinished();
+        } else {
+            collapsePanel(true /* animate */);
+        }
+    }
+
+    @Override
+    public boolean areLaunchAnimationsEnabled() {
+        return mState == StatusBarState.SHADE;
+    }
+
     /**
      * All changes to the status bar and notifications funnel through here and are batched.
      */
@@ -2916,8 +2950,6 @@
         // End old BaseStatusBar.userSwitched
         if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId);
         animateCollapsePanels();
-        updatePublicMode();
-        mEntryManager.getNotificationData().filterAndSort();
         if (mReinflateNotificationsOnUserSwitched) {
             mEntryManager.updateNotificationsOnDensityOrFontScaleChanged();
             mReinflateNotificationsOnUserSwitched = false;
@@ -3350,7 +3382,9 @@
     }
 
     public boolean isCollapsing() {
-        return mNotificationPanel.isCollapsing() || mActivityLaunchAnimator.isAnimationPending();
+        return mNotificationPanel.isCollapsing()
+                || mActivityLaunchAnimator.isAnimationPending()
+                || mActivityLaunchAnimator.isAnimationRunning();
     }
 
     public void addPostCollapseAction(Runnable r) {
@@ -3456,7 +3490,14 @@
         mIsKeyguard = false;
         Trace.beginSection("StatusBar#hideKeyguard");
         boolean staying = mStatusBarStateController.leaveOpenOnKeyguardHide();
-        mStatusBarStateController.setState(StatusBarState.SHADE);
+        if (!(mStatusBarStateController.setState(StatusBarState.SHADE))) {
+            //TODO: StatusBarStateController should probably know about hiding the keyguard and
+            // notify listeners.
+
+            // If the state didn't change, we may still need to update public mode
+            mLockscreenUserManager.updatePublicMode();
+            mEntryManager.updateNotifications();
+        }
         View viewToClick = null;
         if (mStatusBarStateController.leaveOpenOnKeyguardHide()) {
             if (!mKeyguardRequested) {
@@ -3542,34 +3583,6 @@
         mScrimController.setExpansionAffectsAlpha(true);
     }
 
-    // TODO: Move this to NotificationLockscreenUserManager.
-    private void updatePublicMode() {
-        final boolean showingKeyguard = mStatusBarKeyguardViewManager.isShowing();
-        final boolean devicePublic = showingKeyguard
-                && mStatusBarKeyguardViewManager.isSecure(
-                        mLockscreenUserManager.getCurrentUserId());
-
-        // Look for public mode users. Users are considered public in either case of:
-        //   - device keyguard is shown in secure mode;
-        //   - profile is locked with a work challenge.
-        SparseArray<UserInfo> currentProfiles = mLockscreenUserManager.getCurrentProfiles();
-        for (int i = currentProfiles.size() - 1; i >= 0; i--) {
-            final int userId = currentProfiles.valueAt(i).id;
-            boolean isProfilePublic = devicePublic;
-            if (!devicePublic && userId != mLockscreenUserManager.getCurrentUserId()) {
-                // We can't rely on KeyguardManager#isDeviceLocked() for unified profile challenge
-                // due to a race condition where this code could be called before
-                // TrustManagerService updates its internal records, resulting in an incorrect
-                // state being cached in mLockscreenPublicMode. (b/35951989)
-                if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
-                        && mStatusBarKeyguardViewManager.isSecure(userId)) {
-                    isProfilePublic = mKeyguardManager.isDeviceLocked(userId);
-                }
-            }
-            mLockscreenUserManager.setLockscreenPublicMode(isProfilePublic, userId);
-        }
-    }
-
     /**
      * Switches theme from light to dark and vice-versa.
      */
@@ -3599,6 +3612,7 @@
         mKeyguardIndicationController.setDozing(mDozing);
         mNotificationPanel.setDozing(mDozing, animate, mWakeUpTouchLocation);
         mNotificationLogger.setDozing(mDozing);
+        mGroupManager.setDozing(mDozing);
         updateQsExpansionEnabled();
         Trace.endSection();
     }
@@ -3759,8 +3773,6 @@
             }
         }
         updateDozingState();
-        updatePublicMode();
-        mEntryManager.updateNotifications();
         checkBarModes();
         updateScrimController();
         updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
@@ -4013,8 +4025,6 @@
 
     @Override
     public void onWorkChallengeChanged() {
-        updatePublicMode();
-        mEntryManager.updateNotifications();
         if (mPendingWorkRemoteInputView != null
                 && !mLockscreenUserManager.isAnyProfilePublicMode()) {
             // Expand notification panel and the notification row, then click on remote input view
@@ -4145,6 +4155,7 @@
         @Override
         public void onStartedWakingUp() {
             mDeviceInteractive = true;
+            mAmbientPulseManager.releaseAllImmediately();
             mVisualStabilityManager.setScreenOn(true);
             mNotificationPanel.setTouchAndAnimationDisabled(false);
             mDozeServiceHost.stopDozing();
@@ -4177,11 +4188,7 @@
         public void onScreenTurnedOff() {
             mFalsingManager.onScreenOff();
             mScrimController.onScreenTurnedOff();
-            // If we pulse in from AOD, we turn the screen off first. However, updatingIsKeyguard
-            // in that case destroys the HeadsUpManager state, so don't do it in that case.
-            if (!isPulsing()) {
-                updateIsKeyguard();
-            }
+            updateIsKeyguard();
         }
     };
 
@@ -4241,12 +4248,12 @@
 
     @Override
     public void appTransitionCancelled() {
-        EventBus.getDefault().send(new AppTransitionFinishedEvent());
+        getComponent(Divider.class).onAppTransitionFinished();
     }
 
     @Override
     public void appTransitionFinished() {
-        EventBus.getDefault().send(new AppTransitionFinishedEvent());
+        getComponent(Divider.class).onAppTransitionFinished();
     }
 
     @Override
@@ -4420,9 +4427,9 @@
             }
         }
 
-        public void fireNotificationHeadsUp() {
+        public void fireNotificationPulse() {
             for (Callback callback : mCallbacks) {
-                callback.onNotificationHeadsUp();
+                callback.onNotificationAlerted();
             }
         }
 
@@ -4458,7 +4465,7 @@
                 @Override
                 public void onPulseStarted() {
                     callback.onPulseStarted();
-                    if (mHeadsUpManager.hasNotifications()) {
+                    if (mAmbientPulseManager.hasNotifications()) {
                         // Only pulse the stack scroller if there's actually something to show.
                         // Otherwise just show the always-on screen.
                         setPulsing(true);
@@ -4539,7 +4546,11 @@
 
         @Override
         public void extendPulse() {
-            mDozeScrimController.extendPulse();
+            if (mDozeScrimController.isPulsing() && mAmbientPulseManager.hasNotifications()) {
+                mAmbientPulseManager.extendPulse();
+            } else {
+                mDozeScrimController.extendPulse();
+            }
         }
 
         @Override
@@ -4625,6 +4636,8 @@
     // for heads up notifications
     protected HeadsUpManagerPhone mHeadsUpManager;
 
+    protected AmbientPulseManager mAmbientPulseManager = Dependency.get(AmbientPulseManager.class);
+
     private AboveShelfObserver mAboveShelfObserver;
 
     // handling reordering
@@ -4652,6 +4665,7 @@
 
     protected WindowManager mWindowManager;
     protected IWindowManager mWindowManagerService;
+    private IDreamManager mDreamManager;
 
     protected Display mDisplay;
 
@@ -4724,13 +4738,14 @@
                 : notification.fullScreenIntent;
         final String notificationKey = sbn.getKey();
 
-        final boolean afterKeyguardGone = intent.isActivity()
+        boolean isActivityIntent = intent.isActivity();
+        final boolean afterKeyguardGone = isActivityIntent
                 && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
                 mLockscreenUserManager.getCurrentUserId());
         final boolean wasOccluded = mIsOccluded;
         dismissKeyguardThenExecute(() -> {
             // TODO: Some of this code may be able to move to NotificationEntryManager.
-            if (mHeadsUpManager != null && mHeadsUpManager.contains(notificationKey)) {
+            if (mHeadsUpManager != null && mHeadsUpManager.isAlerting(notificationKey)) {
                 // Release the HUN notification to the shade.
 
                 if (isPresenterFullyCollapsed()) {
@@ -4765,7 +4780,7 @@
                     // If we are launching a work activity and require to launch
                     // separate work challenge, we defer the activity action and cancel
                     // notification until work challenge is unlocked.
-                    if (intent.isActivity()) {
+                    if (isActivityIntent) {
                         final int userId = intent.getCreatorUserHandle().getIdentifier();
                         if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
                                 && mKeyguardManager.isDeviceLocked(userId)) {
@@ -4801,7 +4816,7 @@
                         }
                         launchResult = intent.sendAndReturnResult(mContext, 0, fillInIntent, null,
                                 null, null, getActivityOptions(adapter));
-                        mActivityLaunchAnimator.setLaunchResult(launchResult);
+                        mActivityLaunchAnimator.setLaunchResult(launchResult, isActivityIntent);
                     } catch (RemoteException | PendingIntent.CanceledException e) {
                         // the stack trace isn't very helpful here.
                         // Just log the exception message.
@@ -4809,7 +4824,7 @@
 
                         // TODO: Dismiss Keyguard.
                     }
-                    if (intent.isActivity()) {
+                    if (isActivityIntent) {
                         mAssistManager.hideAssist();
                     }
                 }
@@ -4928,7 +4943,7 @@
                         .startActivities(getActivityOptions(
                                 mActivityLaunchAnimator.getLaunchAnimation(row, mIsOccluded)),
                                 new UserHandle(UserHandle.getUserId(appUid)));
-                mActivityLaunchAnimator.setLaunchResult(launchResult);
+                mActivityLaunchAnimator.setLaunchResult(launchResult, true /* isActivityIntent */);
                 if (shouldCollapse()) {
                     // Putting it back on the main thread, since we're touching views
                     mStatusBarWindow.post(() -> animateCollapsePanels(
@@ -4955,7 +4970,13 @@
     }
 
     void awakenDreams() {
-        SystemServicesProxy.getInstance(mContext).awakenDreamsAsync();
+        Dependency.get(UiOffloadThread.class).submit(() -> {
+            try {
+                mDreamManager.awaken();
+            } catch (RemoteException e) {
+                e.printStackTrace();
+            }
+        });
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index e8389af..3db1456 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -460,6 +460,11 @@
                 boolean staying = mStatusBar.hideKeyguard();
                 if (!staying) {
                     mStatusBarWindowController.setKeyguardFadingAway(true);
+                    // hide() will happen asynchronously and might arrive after the scrims
+                    // were already hidden, this means that the transition callback won't
+                    // be triggered anymore and StatusBarWindowController will be forever in
+                    // the fadingAway state.
+                    mStatusBar.updateScrimController();
                     wakeAndUnlockDejank();
                 } else {
                     mStatusBar.finishKeyguardFadingAway();
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 167bba6..57c7e28 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
@@ -93,7 +93,8 @@
         mKeyguardScreenRotation = shouldEnableKeyguardScreenRotation();
         mDozeParameters = dozeParameters;
         mScreenBrightnessDoze = mDozeParameters.getScreenBrightnessDoze();
-        Dependency.get(StatusBarStateController.class).addListener(mStateListener);
+        Dependency.get(StatusBarStateController.class).addListener(
+                mStateListener, StatusBarStateController.RANK_STATUS_BAR_WINDOW_CONTROLLER);
         Dependency.get(ConfigurationController.class).addCallback(this);
     }
 
@@ -135,6 +136,7 @@
         mWindowManager.addView(mStatusBarView, mLp);
         mLpChanged = new WindowManager.LayoutParams();
         mLpChanged.copyFrom(mLp);
+        onThemeChanged();
     }
 
     public void setDozeScreenBrightness(int value) {
@@ -483,6 +485,10 @@
 
     @Override
     public void onThemeChanged() {
+        if (mStatusBarView == null) {
+            return;
+        }
+
         StatusBarStateController state = Dependency.get(StatusBarStateController.class);
         int which;
         if (state.getState() == StatusBarState.KEYGUARD
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index 3c16329..0a72c3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -17,10 +17,7 @@
 package com.android.systemui.statusbar.policy;
 
 import android.app.ActivityManager;
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.net.ConnectivityManager;
 import android.net.wifi.WifiManager;
 import android.os.UserManager;
@@ -38,14 +35,13 @@
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private final ArrayList<Callback> mCallbacks = new ArrayList<>();
-    private final WifiStateReceiver mWifiStateReceiver = new WifiStateReceiver();
     private final ConnectivityManager mConnectivityManager;
     private final WifiManager mWifiManager;
     private final Context mContext;
 
     private int mHotspotState;
     private int mNumConnectedDevices;
-    private boolean mWaitingForCallback;
+    private boolean mWaitingForTerminalState;
 
     public HotspotControllerImpl(Context context) {
         mContext = context;
@@ -63,7 +59,9 @@
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("HotspotController state:");
-        pw.print("  mHotspotEnabled="); pw.println(stateToString(mHotspotState));
+        pw.print("  mHotspotState="); pw.println(stateToString(mHotspotState));
+        pw.print("  mNumConnectedDevices="); pw.println(mNumConnectedDevices);
+        pw.print("  mWaitingForTerminalState="); pw.println(mWaitingForTerminalState);
     }
 
     private static String stateToString(int hotspotState) {
@@ -99,7 +97,6 @@
         if (DEBUG) Log.d(TAG, "removeCallback " + callback);
         synchronized (mCallbacks) {
             mCallbacks.remove(callback);
-
             updateWifiStateListeners(!mCallbacks.isEmpty());
         }
     }
@@ -112,7 +109,6 @@
      * @param shouldListen whether we should start listening to various wifi statuses
      */
     private void updateWifiStateListeners(boolean shouldListen) {
-        mWifiStateReceiver.setListening(shouldListen);
         if (shouldListen) {
             mWifiManager.registerSoftApCallback(
                     this,
@@ -129,21 +125,27 @@
 
     @Override
     public boolean isHotspotTransient() {
-        return mWaitingForCallback || (mHotspotState == WifiManager.WIFI_AP_STATE_ENABLING);
+        return mWaitingForTerminalState || (mHotspotState == WifiManager.WIFI_AP_STATE_ENABLING);
     }
 
     @Override
     public void setHotspotEnabled(boolean enabled) {
-        if (mWaitingForCallback) {
-            if (DEBUG) Log.d(TAG, "Ignoring setHotspotEnabled; waiting for callback.");
+        if (mWaitingForTerminalState) {
+            if (DEBUG) Log.d(TAG, "Ignoring setHotspotEnabled; waiting for terminal state.");
             return;
         }
         if (enabled) {
-            OnStartTetheringCallback callback = new OnStartTetheringCallback();
-            mWaitingForCallback = true;
+            mWaitingForTerminalState = true;
             if (DEBUG) Log.d(TAG, "Starting tethering");
-            mConnectivityManager.startTethering(
-                    ConnectivityManager.TETHERING_WIFI, false, callback);
+            mConnectivityManager.startTethering(ConnectivityManager.TETHERING_WIFI, false,
+                    new ConnectivityManager.OnStartTetheringCallback() {
+                        @Override
+                        public void onTetheringFailed() {
+                            if (DEBUG) Log.d(TAG, "onTetheringFailed");
+                            maybeResetSoftApState();
+                            fireHotspotChangedCallback();
+                        }
+                    });
         } else {
             mConnectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
         }
@@ -155,97 +157,56 @@
     }
 
     /**
-     * Sends a hotspot changed callback with the new enabled status. Wraps
-     * {@link #fireHotspotChangedCallback(boolean, int)} and assumes that the number of devices has
-     * not changed.
-     *
-     * @param enabled whether the hotspot is enabled
+     * Sends a hotspot changed callback.
+     * Be careful when calling over multiple threads, especially if one of them is the main thread
+     * (as it can be blocked).
      */
-    private void fireHotspotChangedCallback(boolean enabled) {
-        fireHotspotChangedCallback(enabled, mNumConnectedDevices);
-    }
-
-    /**
-     * Sends a hotspot changed callback with the new enabled status & the number of devices
-     * connected to the hotspot. Be careful when calling over multiple threads, especially if one of
-     * them is the main thread (as it can be blocked).
-     *
-     * @param enabled whether the hotspot is enabled
-     * @param numConnectedDevices number of devices connected to the hotspot
-     */
-    private void fireHotspotChangedCallback(boolean enabled, int numConnectedDevices) {
+    private void fireHotspotChangedCallback() {
         synchronized (mCallbacks) {
             for (Callback callback : mCallbacks) {
-                callback.onHotspotChanged(enabled, numConnectedDevices);
+                callback.onHotspotChanged(isHotspotEnabled(), mNumConnectedDevices);
             }
         }
     }
 
     @Override
     public void onStateChanged(int state, int failureReason) {
-        // Do nothing - we don't care about changing anything here.
+        // Update internal hotspot state for tracking before using any enabled/callback methods.
+        mHotspotState = state;
+
+        maybeResetSoftApState();
+        if (!isHotspotEnabled()) {
+            // Reset num devices if the hotspot is no longer enabled so we don't get ghost
+            // counters.
+            mNumConnectedDevices = 0;
+        }
+
+        fireHotspotChangedCallback();
+    }
+
+    private void maybeResetSoftApState() {
+        if (!mWaitingForTerminalState) {
+            return; // Only reset soft AP state if enabled from this controller.
+        }
+        switch (mHotspotState) {
+            case WifiManager.WIFI_AP_STATE_FAILED:
+                // TODO(b/110697252): must be called to reset soft ap state after failure
+                mConnectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
+                // Fall through
+            case WifiManager.WIFI_AP_STATE_ENABLED:
+            case WifiManager.WIFI_AP_STATE_DISABLED:
+                mWaitingForTerminalState = false;
+                break;
+            case WifiManager.WIFI_AP_STATE_ENABLING:
+            case WifiManager.WIFI_AP_STATE_DISABLING:
+            default:
+                break;
+        }
     }
 
     @Override
     public void onNumClientsChanged(int numConnectedDevices) {
         mNumConnectedDevices = numConnectedDevices;
-        fireHotspotChangedCallback(isHotspotEnabled(), numConnectedDevices);
-    }
-
-    private final class OnStartTetheringCallback extends
-            ConnectivityManager.OnStartTetheringCallback {
-        @Override
-        public void onTetheringStarted() {
-            if (DEBUG) Log.d(TAG, "onTetheringStarted");
-            mWaitingForCallback = false;
-            // Don't fire a callback here, instead wait for the next update from wifi.
-        }
-
-        @Override
-        public void onTetheringFailed() {
-            if (DEBUG) Log.d(TAG, "onTetheringFailed");
-            mWaitingForCallback = false;
-            fireHotspotChangedCallback(isHotspotEnabled());
-          // TODO: Show error.
-        }
-    }
-
-    /**
-     * Class to listen in on wifi state and update the hotspot state
-     */
-    private final class WifiStateReceiver extends BroadcastReceiver {
-        private boolean mRegistered;
-
-        public void setListening(boolean listening) {
-            if (listening && !mRegistered) {
-                if (DEBUG) Log.d(TAG, "Registering receiver");
-                final IntentFilter filter = new IntentFilter();
-                filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
-                mContext.registerReceiver(this, filter);
-                mRegistered = true;
-            } else if (!listening && mRegistered) {
-                if (DEBUG) Log.d(TAG, "Unregistering receiver");
-                mContext.unregisterReceiver(this);
-                mRegistered = false;
-            }
-        }
-
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            int state = intent.getIntExtra(
-                    WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_FAILED);
-            if (DEBUG) Log.d(TAG, "onReceive " + state);
-
-            // Update internal hotspot state for tracking before using any enabled/callback methods.
-            mHotspotState = state;
-
-            if (!isHotspotEnabled()) {
-                // Reset num devices if the hotspot is no longer enabled so we don't get ghost
-                // counters.
-                mNumConnectedDevices = 0;
-            }
-
-            fireHotspotChangedCallback(isHotspotEnabled());
-        }
+        fireHotspotChangedCallback();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
index 945d9b9..2340786 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
@@ -19,6 +19,7 @@
 import android.animation.ArgbEvaluator;
 import android.annotation.ColorInt;
 import android.annotation.DrawableRes;
+import android.annotation.NonNull;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -35,6 +36,7 @@
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable;
 import android.util.FloatProperty;
+import android.view.ContextThemeWrapper;
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
 
@@ -388,6 +390,23 @@
         }
     }
 
+    /**
+     * Creates a KeyButtonDrawable with a shadow given its icon. The tint applied to the drawable
+     * is determined by the dark and light theme given by the context.
+     * @param ctx Context to get the drawable and determine the dark and light theme
+     * @param icon the icon resource id
+     * @param hasShadow if a shadow will appear with the drawable
+     * @return KeyButtonDrawable
+     */
+    public static KeyButtonDrawable create(@NonNull Context ctx, @DrawableRes int icon,
+        boolean hasShadow) {
+        final int dualToneDarkTheme = Utils.getThemeAttr(ctx, R.attr.darkIconTheme);
+        final int dualToneLightTheme = Utils.getThemeAttr(ctx, R.attr.lightIconTheme);
+        Context lightContext = new ContextThemeWrapper(ctx, dualToneLightTheme);
+        Context darkContext = new ContextThemeWrapper(ctx, dualToneDarkTheme);
+        return KeyButtonDrawable.create(lightContext, darkContext, icon, hasShadow);
+    }
+
     public static KeyButtonDrawable create(Context lightContext, Context darkContext,
         @DrawableRes int iconResId, boolean hasShadow) {
         return create(lightContext,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 52b813f..7dd0d0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -586,7 +586,8 @@
             final InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
 
             if (mShowImeOnInputConnection && inputConnection != null) {
-                final InputMethodManager imm = InputMethodManager.getInstance();
+                final InputMethodManager imm =
+                        getContext().getSystemService(InputMethodManager.class);
                 if (imm != null) {
                     // onCreateInputConnection is called by InputMethodManager in the middle of
                     // setting up the connection to the IME; wait with requesting the IME until that
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index 0adb439..29a6b95 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -403,7 +403,7 @@
                 boolean hasCACerts = !(conn.getService().getUserCaAliases().getList().isEmpty());
                 return new Pair<Integer, Boolean>(userId[0], hasCACerts);
             } catch (RemoteException | InterruptedException | AssertionError e) {
-                Log.i(TAG, e.getMessage());
+                Log.i(TAG, "failed to get CA certs", e);
                 new Handler(Dependency.get(Dependency.BG_LOOPER)).postDelayed(
                         () -> new CACertLoader().execute(userId[0]),
                         CA_CERT_LOADING_RETRY_TIME_IN_MS);
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 8b1324a..e73c70b 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -17,6 +17,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     xmlns:tools="http://schemas.android.com/tools"
+    android:sharedUserId="android.uid.system"
     package="com.android.systemui.tests">
 
     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewTest.kt
new file mode 100644
index 0000000..cfe9818
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewTest.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.keyguard
+
+import android.support.test.filters.SmallTest
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.LayoutInflater
+
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class KeyguardPatternViewTest : SysuiTestCase() {
+
+    private lateinit var mKeyguardPatternView: KeyguardPatternView
+    private lateinit var mSecurityMessage: KeyguardMessageArea
+
+    @Before
+    fun setup() {
+        val inflater = LayoutInflater.from(context)
+        mKeyguardPatternView = inflater.inflate(R.layout.keyguard_pattern_view, null)
+                as KeyguardPatternView
+        mSecurityMessage = KeyguardMessageArea.findSecurityMessageDisplay(mKeyguardPatternView)
+                as KeyguardMessageArea
+    }
+
+    @Test
+    fun onResume_clearsTextField() {
+        mSecurityMessage.setMessage("an old message")
+        mKeyguardPatternView.onResume(KeyguardSecurityView.SCREEN_ON)
+        assertThat(mSecurityMessage.text).isEqualTo("")
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
index eaa0dcf..1cf73b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
@@ -33,6 +33,7 @@
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 
+import android.content.Intent;
 import android.os.PowerManager;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -71,7 +72,8 @@
         mSensor = mSensorManager.getFakeLightSensor();
         mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager,
                 mSensor.getSensor(), mHostFake, null /* handler */,
-                DEFAULT_BRIGHTNESS, SENSOR_TO_BRIGHTNESS, SENSOR_TO_OPACITY);
+                DEFAULT_BRIGHTNESS, SENSOR_TO_BRIGHTNESS, SENSOR_TO_OPACITY,
+                true /* debuggable */);
     }
 
     @Test
@@ -93,6 +95,19 @@
     }
 
     @Test
+    public void testAod_usesDebugValue() throws Exception {
+        mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+        mScreen.transitionTo(INITIALIZED, DOZE_AOD);
+
+        Intent intent = new Intent(DozeScreenBrightness.ACTION_AOD_BRIGHTNESS);
+        intent.putExtra(DozeScreenBrightness.BRIGHTNESS_BUCKET, 1);
+        mScreen.onReceive(mContext, intent);
+        mSensor.sendSensorEvent(3);
+
+        assertEquals(1, mServiceFake.screenBrightness);
+    }
+
+    @Test
     public void testAod_usesLightSensorRespectingUserSetting() throws Exception {
         int maxBrightness = 3;
         Settings.System.putIntForUser(mContext.getContentResolver(),
@@ -160,7 +175,8 @@
     public void testNullSensor() throws Exception {
         mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager,
                 null /* sensor */, mHostFake, null /* handler */,
-                DEFAULT_BRIGHTNESS, SENSOR_TO_BRIGHTNESS, SENSOR_TO_OPACITY);
+                DEFAULT_BRIGHTNESS, SENSOR_TO_BRIGHTNESS, SENSOR_TO_OPACITY,
+                true /* debuggable */);
 
         mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
         mScreen.transitionTo(INITIALIZED, DOZE_AOD);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index c2da7f5..5c8336c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -88,14 +88,14 @@
         mTriggers.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
         mTriggers.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE);
 
-        mHost.callback.onNotificationHeadsUp();
+        mHost.callback.onNotificationAlerted();
 
         mSensors.getMockProximitySensor().sendProximityResult(false); /* Near */
 
         verify(mMachine, never()).requestState(any());
         verify(mMachine, never()).requestPulse(anyInt());
 
-        mHost.callback.onNotificationHeadsUp();
+        mHost.callback.onNotificationAlerted();
 
         mSensors.getMockProximitySensor().sendProximityResult(true); /* Far */
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
index f8aa28d..199c4c2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
@@ -40,9 +40,9 @@
 import android.support.test.runner.AndroidJUnit4;
 
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 
+import com.android.systemui.shared.system.TaskStackChangeListener;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -65,7 +65,7 @@
     private @Mock IActivityTaskManager mIActivityTaskManager;
 
     private WorkLockActivityController mController;
-    private SysUiTaskStackChangeListener mTaskStackListener;
+    private TaskStackChangeListener mTaskStackListener;
 
     @Before
     public void setUp() throws Exception {
@@ -75,8 +75,8 @@
         doReturn("com.example.test").when(mContext).getPackageName();
 
         // Construct controller. Save the TaskStackListener for injecting events.
-        final ArgumentCaptor<SysUiTaskStackChangeListener> listenerCaptor =
-                ArgumentCaptor.forClass(SysUiTaskStackChangeListener.class);
+        final ArgumentCaptor<TaskStackChangeListener> listenerCaptor =
+                ArgumentCaptor.forClass(TaskStackChangeListener.class);
         mController = new WorkLockActivityController(mContext, mActivityManager,
                 mIActivityTaskManager);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
index 04441ab..19974f8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
@@ -64,6 +64,7 @@
 @RunWith(AndroidJUnit4.class)
 public class PluginInstanceManagerTest extends SysuiTestCase {
 
+    private static final String WHITELISTED_PACKAGE = "com.android.systemui";
     // Static since the plugin needs to be generated by the PluginInstanceManager using newInstance.
     private static Plugin sMockPlugin;
 
@@ -88,7 +89,7 @@
         mMockVersionInfo = mock(VersionInfo.class);
         mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
                 mMockListener, true, mHandlerThread.getLooper(), mMockVersionInfo,
-                mMockManager, true);
+                mMockManager, true, new String[0]);
         sMockPlugin = mock(Plugin.class);
         when(sMockPlugin.getVersion()).thenReturn(1);
     }
@@ -186,7 +187,7 @@
         // Create a version that thinks the build is not debuggable.
         mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
                 mMockListener, true, mHandlerThread.getLooper(), mMockVersionInfo,
-                mMockManager, false);
+                mMockManager, false, new String[0]);
         setupFakePmQuery();
 
         mPluginInstanceManager.loadAll();
@@ -199,6 +200,25 @@
     }
 
     @Test
+    public void testNonDebuggable_whitelist() throws Exception {
+        // Create a version that thinks the build is not debuggable.
+        mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
+                mMockListener, true, mHandlerThread.getLooper(), mMockVersionInfo,
+                mMockManager, false, new String[] {WHITELISTED_PACKAGE});
+        setupFakePmQuery();
+
+        mPluginInstanceManager.loadAll();
+
+        waitForIdleSync(mPluginInstanceManager.mPluginHandler);
+        waitForIdleSync(mPluginInstanceManager.mMainHandler);
+
+        // Verify startup lifecycle
+        verify(sMockPlugin).onCreate(ArgumentCaptor.forClass(Context.class).capture(),
+                ArgumentCaptor.forClass(Context.class).capture());
+        verify(mMockListener).onPluginConnected(any(), any());
+    }
+
+    @Test
     public void testCheckAndDisable() throws Exception {
         createPlugin(); // Get into valid created state.
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
index 94dbc2a..438f9e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
@@ -13,8 +13,9 @@
  */
 package com.android.systemui.plugins;
 
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertSame;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -26,8 +27,6 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.net.Uri;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -36,11 +35,10 @@
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.annotations.ProvidesInterface;
 import com.android.systemui.plugins.PluginInstanceManager.PluginInfo;
 import com.android.systemui.plugins.PluginManagerImpl.PluginInstanceManagerFactory;
+import com.android.systemui.plugins.annotations.ProvidesInterface;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -54,6 +52,8 @@
 @RunWithLooper
 public class PluginManagerTest extends SysuiTestCase {
 
+    private static final String WHITELISTED_PACKAGE = "com.android.systemui";
+
     private PluginInstanceManagerFactory mMockFactory;
     private PluginInstanceManager mMockPluginInstance;
     private PluginManagerImpl mPluginManager;
@@ -74,7 +74,7 @@
         when(mMockFactory.createPluginInstanceManager(Mockito.any(), Mockito.any(), Mockito.any(),
                 Mockito.anyBoolean(), Mockito.any(), Mockito.any(), Mockito.any()))
                 .thenReturn(mMockPluginInstance);
-        mPluginManager = new PluginManagerImpl(getContext(), mMockFactory, true,
+        mPluginManager = new PluginManagerImpl(getContext(), mMockFactory, true, new String[0],
                 mMockExceptionHandler);
         resetExceptionHandler();
         mMockListener = mock(PluginListener.class);
@@ -87,7 +87,7 @@
         when(mMockPluginInstance.getPlugin()).thenReturn(new PluginInfo(null, null, mockPlugin,
                 null, null));
         Plugin result = mPluginManager.getOneShotPlugin("myAction", TestPlugin.class);
-        assertTrue(result == mockPlugin);
+        assertSame(mockPlugin, result);
     }
 
     @Test
@@ -106,16 +106,27 @@
     }
 
     @Test
-    public void testNonDebuggable() {
+    @RunWithLooper(setAsMainLooper = true)
+    public void testNonDebuggable_noWhitelist() {
         mPluginManager = new PluginManagerImpl(getContext(), mMockFactory, false,
-                mMockExceptionHandler);
+                new String[0], mMockExceptionHandler);
         resetExceptionHandler();
 
         mPluginManager.addPluginListener("myAction", mMockListener, TestPlugin.class);
-        verify(mMockPluginInstance, Mockito.never()).loadAll();
-
         assertNull(mPluginManager.getOneShotPlugin("myPlugin", TestPlugin.class));
-        verify(mMockPluginInstance, Mockito.never()).getPlugin();
+        assertNull(mPluginManager.getClassLoader("myPlugin", WHITELISTED_PACKAGE));
+    }
+
+    @Test
+    @RunWithLooper(setAsMainLooper = true)
+    public void testNonDebuggable_whitelistedPkg() {
+        mPluginManager = new PluginManagerImpl(getContext(), mMockFactory, false,
+                new String[] {WHITELISTED_PACKAGE}, mMockExceptionHandler);
+        resetExceptionHandler();
+
+        mPluginManager.addPluginListener("myAction", mMockListener, TestPlugin.class);
+        assertNotNull(mPluginManager.getClassLoader("myPlugin", WHITELISTED_PACKAGE));
+        assertNull(mPluginManager.getClassLoader("myPlugin", "com.android.invalidpackage"));
     }
 
     @Test
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 f21ce27..8b41516 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
@@ -56,19 +56,19 @@
     private static final String TEST_PACKAGE_NAME = "test";
     private static final int TEST_UID = 0;
 
-    private static final int TEST_MINIMUM_DISPLAY_TIME = 200;
-    private static final int TEST_AUTO_DISMISS_TIME = 500;
+    protected static final int TEST_MINIMUM_DISPLAY_TIME = 200;
+    protected static final int TEST_AUTO_DISMISS_TIME = 500;
     // Number of notifications to use in tests requiring multiple notifications
     private static final int TEST_NUM_NOTIFICATIONS = 4;
-    private static final int TEST_TIMEOUT_TIME = 10000;
-    private final Runnable TEST_TIMEOUT_RUNNABLE = () -> mTimedOut = true;
+    protected static final int TEST_TIMEOUT_TIME = 10000;
+    protected final Runnable TEST_TIMEOUT_RUNNABLE = () -> mTimedOut = true;
 
     private AlertingNotificationManager mAlertingNotificationManager;
 
     protected NotificationData.Entry mEntry;
     protected Handler mTestHandler;
     private StatusBarNotification mSbn;
-    private boolean mTimedOut = false;
+    protected boolean mTimedOut = false;
 
     @Mock protected ExpandableNotificationRow mRow;
 
@@ -122,7 +122,7 @@
     public void testShowNotification_addsEntry() {
         mAlertingNotificationManager.showNotification(mEntry);
 
-        assertTrue(mAlertingNotificationManager.contains(mEntry.key));
+        assertTrue(mAlertingNotificationManager.isAlerting(mEntry.key));
         assertTrue(mAlertingNotificationManager.hasNotifications());
         assertEquals(mEntry, mAlertingNotificationManager.getEntry(mEntry.key));
     }
@@ -136,7 +136,7 @@
         TestableLooper.get(this).processMessages(1);
 
         assertFalse("Test timed out", mTimedOut);
-        assertFalse(mAlertingNotificationManager.contains(mEntry.key));
+        assertFalse(mAlertingNotificationManager.isAlerting(mEntry.key));
     }
 
     @Test
@@ -146,7 +146,7 @@
         // Try to remove but defer, since the notification has not been shown long enough.
         mAlertingNotificationManager.removeNotification(mEntry.key, false /* releaseImmediately */);
 
-        assertTrue(mAlertingNotificationManager.contains(mEntry.key));
+        assertTrue(mAlertingNotificationManager.isAlerting(mEntry.key));
     }
 
     @Test
@@ -156,7 +156,7 @@
         // Remove forcibly with releaseImmediately = true.
         mAlertingNotificationManager.removeNotification(mEntry.key, true /* releaseImmediately */);
 
-        assertFalse(mAlertingNotificationManager.contains(mEntry.key));
+        assertFalse(mAlertingNotificationManager.isAlerting(mEntry.key));
     }
 
     @Test
@@ -174,10 +174,18 @@
     }
 
     @Test
-    public void testShouldExtendLifetime_notShownLongEnough() {
+    public void testCanRemoveImmediately_notShownLongEnough() {
         mAlertingNotificationManager.showNotification(mEntry);
 
-        // The entry has just been added so the lifetime should be extended
+        // The entry has just been added so we should not remove immediately.
+        assertFalse(mAlertingNotificationManager.canRemoveImmediately(mEntry.key));
+    }
+
+    @Test
+    public void testShouldExtendLifetime() {
+        mAlertingNotificationManager.showNotification(mEntry);
+
+        // While the entry is alerting, it should not be removable.
         assertTrue(mAlertingNotificationManager.shouldExtendLifetime(mEntry));
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AmbientPulseManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AmbientPulseManagerTest.java
new file mode 100644
index 0000000..f0344e6
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AmbientPulseManagerTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class AmbientPulseManagerTest extends AlertingNotificationManagerTest {
+    @Rule
+    public MockitoRule rule = MockitoJUnit.rule();
+
+    private static final int TEST_EXTENSION_TIME = 500;
+    private AmbientPulseManager mAmbientPulseManager;
+    private boolean mLivesPastNormalTime;
+
+    protected AlertingNotificationManager createAlertingNotificationManager() {
+        return mAmbientPulseManager;
+    }
+
+    @Before
+    public void setUp() {
+        mAmbientPulseManager = new AmbientPulseManager(mContext);
+        mAmbientPulseManager.mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
+        mAmbientPulseManager.mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;
+        mAmbientPulseManager.mExtensionTime = TEST_EXTENSION_TIME;
+        super.setUp();
+        mAmbientPulseManager.mHandler = mTestHandler;
+    }
+
+    @Test
+    public void testExtendPulse() {
+        mAmbientPulseManager.showNotification(mEntry);
+        Runnable pastNormalTimeRunnable =
+                () -> mLivesPastNormalTime = mAmbientPulseManager.isAlerting(mEntry.key);
+        mTestHandler.postDelayed(pastNormalTimeRunnable,
+                mAmbientPulseManager.mAutoDismissNotificationDecay +
+                        mAmbientPulseManager.mExtensionTime / 2);
+        mTestHandler.postDelayed(TEST_TIMEOUT_RUNNABLE, TEST_TIMEOUT_TIME);
+
+        mAmbientPulseManager.extendPulse();
+
+        // Wait for normal time runnable and extended remove runnable and process them on arrival.
+        TestableLooper.get(this).processMessages(2);
+
+        assertFalse("Test timed out", mTimedOut);
+        assertTrue("Pulse was not extended", mLivesPastNormalTime);
+        assertFalse(mAmbientPulseManager.isAlerting(mEntry.key));
+    }
+}
+
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
index 09c1931..da59450 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
@@ -79,13 +79,14 @@
                 Dependency.get(NotificationLockscreenUserManager.class);
         NotificationViewHierarchyManager viewHierarchyManager =
                 Dependency.get(NotificationViewHierarchyManager.class);
+        NotificationGroupManager groupManager = Dependency.get(NotificationGroupManager.class);
 
         when(mPresenter.getNotificationLockscreenUserManager()).thenReturn(lockscreenUserManager);
-        when(mPresenter.getGroupManager()).thenReturn(
-                Dependency.get(NotificationGroupManager.class));
+        when(mPresenter.getGroupManager()).thenReturn(groupManager);
 
         entryManager.setUpWithPresenter(mPresenter, mListContainer, mEntryManagerCallback,
                 mHeadsUpManager);
+        groupManager.setHeadsUpManager(mHeadsUpManager);
         gutsManager.setUpWithPresenter(mPresenter, mListContainer, mCheckSaveListener,
                 mOnClickListener);
         notificationLogger.setUpWithEntryManager(entryManager, mListContainer);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
index a7758a6..515c109 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -40,8 +40,11 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import android.util.Log;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 
 import com.google.android.collect.Lists;
@@ -61,7 +64,9 @@
 
     // Dependency mocks:
     @Mock private NotificationEntryManager mEntryManager;
+    @Mock private NotificationData mNotificationData;
     @Mock private DeviceProvisionedController mDeviceProvisionedController;
+    @Mock private StatusBarKeyguardViewManager mKeyguardViewManager;
 
     private int mCurrentUserId;
     private TestNotificationLockscreenUserManager mLockscreenUserManager;
@@ -79,9 +84,11 @@
         when(mUserManager.getProfiles(mCurrentUserId)).thenReturn(Lists.newArrayList(
                 new UserInfo(mCurrentUserId, "", 0), new UserInfo(mCurrentUserId + 1, "", 0)));
         when(mPresenter.getHandler()).thenReturn(Handler.createAsync(Looper.myLooper()));
+        when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
 
         mLockscreenUserManager = new TestNotificationLockscreenUserManager(mContext);
         mLockscreenUserManager.setUpWithPresenter(mPresenter, mEntryManager);
+        mLockscreenUserManager.setKeyguardViewManager(mKeyguardViewManager);
     }
 
     @Test
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 b2170fa..edf29ac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
@@ -31,6 +31,7 @@
 import android.view.LayoutInflater;
 import android.widget.RemoteViews;
 
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.row.NotificationInflaterTest;
@@ -63,6 +64,7 @@
         mContext = context;
         mInstrumentation = InstrumentationRegistry.getInstrumentation();
         mHeadsUpManager = new HeadsUpManagerPhone(mContext, null, mGroupManager, null, null);
+        mGroupManager.setHeadsUpManager(mHeadsUpManager);
     }
 
     public ExpandableNotificationRow createRow() throws Exception {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimatorTest.java
new file mode 100644
index 0000000..435ede4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimatorTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyObject;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.RemoteAnimationAdapter;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.NotificationTestHelper;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
+import com.android.systemui.statusbar.phone.StatusBarWindowView;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.stubbing.Answer;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class ActivityLaunchAnimatorTest extends SysuiTestCase {
+
+    private ActivityLaunchAnimator mLaunchAnimator;
+    private ActivityLaunchAnimator.Callback mCallback = mock(ActivityLaunchAnimator.Callback.class);
+    private StatusBarWindowView mStatusBarWindowView = mock(StatusBarWindowView.class);
+    private NotificationListContainer mNotificationContainer
+            = mock(NotificationListContainer.class);
+    private ExpandableNotificationRow mRow = mock(ExpandableNotificationRow.class);
+
+    @Before
+    public void setUp() throws Exception {
+        when(mCallback.areLaunchAnimationsEnabled()).thenReturn(true);
+        mLaunchAnimator = new ActivityLaunchAnimator(
+                mStatusBarWindowView,
+                mCallback,
+                mock(NotificationPanelView.class),
+                mNotificationContainer);
+
+    }
+
+    @Test
+    public void testReturnsNullIfNotEnabled() {
+        when(mCallback.areLaunchAnimationsEnabled()).thenReturn(false);
+        RemoteAnimationAdapter launchAnimation = mLaunchAnimator.getLaunchAnimation(mRow,
+                false /* occluded */);
+        Assert.assertTrue("The LaunchAnimator generated an animation even though animations are "
+                        + "disabled", launchAnimation == null);
+    }
+
+    @Test
+    public void testNotWorkingWhenOccluded() {
+        when(mCallback.areLaunchAnimationsEnabled()).thenReturn(false);
+        RemoteAnimationAdapter launchAnimation = mLaunchAnimator.getLaunchAnimation(mRow,
+                true /* occluded */);
+        Assert.assertTrue("The LaunchAnimator generated an animation even though we're occluded",
+                launchAnimation == null);
+    }
+
+    @Test
+    public void testTimeoutCalled() {
+        RemoteAnimationAdapter launchAnimation = mLaunchAnimator.getLaunchAnimation(mRow,
+                false /* occluded */);
+        Assert.assertTrue("No animation generated", launchAnimation != null);
+        executePostsImmediately(mStatusBarWindowView);
+        mLaunchAnimator.setLaunchResult(ActivityManager.START_SUCCESS,
+                true /* wasIntentActivity */);
+        verify(mCallback).onExpandAnimationTimedOut();
+    }
+
+    private void executePostsImmediately(View view) {
+        doAnswer((i) -> {
+            Runnable run = i.getArgument(0);
+            run.run();
+            return null;
+        }).when(view).post(any());
+        doAnswer((i) -> {
+            Runnable run = i.getArgument(0);
+            run.run();
+            return null;
+        }).when(view).postDelayed(any(), anyLong());
+    }
+}
+
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
index c236fbe..ca968a8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
@@ -158,6 +158,11 @@
         PollingCheck.waitFor(1000,
                 () -> VISIBLE == mNotificationInfo.findViewById(R.id.confirmation).getVisibility());
     }
+    private void ensureNoUndoButton() {
+        PollingCheck.waitFor(1000,
+                () -> GONE == mNotificationInfo.findViewById(R.id.confirmation).getVisibility()
+                        && !mNotificationInfo.isAnimating());
+    }
     private void waitForStopButton() {
         PollingCheck.waitFor(1000,
                 () -> VISIBLE == mNotificationInfo.findViewById(R.id.prompt).getVisibility());
@@ -583,9 +588,6 @@
                 true /* isUserSentimentNegative */);
 
         mNotificationInfo.findViewById(R.id.block).performClick();
-        waitForUndoButton();
-        mNotificationInfo.handleCloseControls(true /* save */, false /* force */);
-
         mTestableLooper.processAllMessages();
         verify(listener).checkSave(any(Runnable.class), eq(mSbn));
     }
@@ -805,7 +807,7 @@
     }
 
     @Test
-    public void testCloseControlsDoesNotUpdateIfCheckSaveListenerIsNoOp() throws Exception {
+    public void testBlockDoesNothingIfCheckSaveListenerIsNoOp() throws Exception {
         mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
@@ -813,10 +815,10 @@
                 }, null, null, true, true);
 
         mNotificationInfo.findViewById(R.id.block).performClick();
-        waitForUndoButton();
+        mTestableLooper.processAllMessages();
+        ensureNoUndoButton();
         mNotificationInfo.handleCloseControls(true, false);
 
-        mTestableLooper.processAllMessages();
         verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
                 eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel));
     }
@@ -831,6 +833,10 @@
                 }, null, null, true, false);
 
         mNotificationInfo.findViewById(R.id.block).performClick();
+        mTestableLooper.processAllMessages();
+        verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
+                eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel));
+
         waitForUndoButton();
         mNotificationInfo.handleCloseControls(true, false);
 
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 06265e5..18dd1fd 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
@@ -15,10 +15,15 @@
 package com.android.systemui.statusbar.notification.row;
 
 import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.doNothing;
 
 import android.app.Notification;
 import android.service.notification.StatusBarNotification;
@@ -27,7 +32,6 @@
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 import android.testing.ViewUtils;
-import android.testing.ViewUtils;
 import android.view.ViewGroup;
 
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
@@ -36,6 +40,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mockito;
 
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper(setAsMainLooper = true)
@@ -72,6 +77,7 @@
         row.resetMenu();
     }
 
+
     @Test
     public void testNoAppOpsInSlowSwipe() {
         NotificationMenuRow row = new NotificationMenuRow(mContext);
@@ -86,4 +92,255 @@
         // one for snooze and one for noti blocking
         assertEquals(2, container.getChildCount());
     }
+
+    @Test
+    public void testIsSnappedAndOnSameSide() {
+        NotificationMenuRow row = Mockito.spy(new NotificationMenuRow((mContext)));
+
+        when(row.isMenuVisible()).thenReturn(true);
+        when(row.isMenuSnapped()).thenReturn(true);
+        when(row.isMenuOnLeft()).thenReturn(true);
+        when(row.isMenuSnappedOnLeft()).thenReturn(true);
+
+        assertTrue("Showing on left and on left", row.isSnappedAndOnSameSide());
+
+
+        when(row.isMenuOnLeft()).thenReturn(false);
+        when(row.isMenuSnappedOnLeft()).thenReturn(false);
+        assertTrue("Snapped to right and on right", row.isSnappedAndOnSameSide());
+
+        when(row.isMenuOnLeft()).thenReturn(true);
+        when(row.isMenuSnapped()).thenReturn(false);
+        assertFalse("Snapped to right and on left", row.isSnappedAndOnSameSide());
+
+        when(row.isMenuOnLeft()).thenReturn(true);
+        when(row.isMenuSnappedOnLeft()).thenReturn(true);
+        when(row.isMenuVisible()).thenReturn(false);
+        assertFalse("Snapped to left and on left, but menu not visible",
+                row.isSnappedAndOnSameSide());
+
+        when(row.isMenuVisible()).thenReturn(true);
+        when(row.isMenuSnapped()).thenReturn(false);
+        assertFalse("Snapped to left and on left, but not actually snapped to",
+                row.isSnappedAndOnSameSide());
+    }
+
+    @Test
+    public void testGetMenuSnapTarget() {
+        NotificationMenuRow row = Mockito.spy(new NotificationMenuRow((mContext)));
+        when(row.isMenuOnLeft()).thenReturn(true);
+        doReturn(30).when(row).getSpaceForMenu();
+
+        assertEquals("When on left, snap target is space for menu",
+                30, row.getMenuSnapTarget());
+
+        when(row.isMenuOnLeft()).thenReturn(false);
+        assertEquals("When on right, snap target is negative space for menu",
+                -30, row.getMenuSnapTarget());
+    }
+
+    @Test
+    public void testIsSwipedEnoughToShowMenu() {
+        NotificationMenuRow row = Mockito.spy(new NotificationMenuRow((mContext)));
+        when(row.isMenuVisible()).thenReturn(true);
+        when(row.isMenuOnLeft()).thenReturn(true);
+        doReturn(40f).when(row).getMinimumSwipeDistance();
+
+        when(row.getTranslation()).thenReturn(30f);
+        assertFalse("on left, translation is less than min", row.isSwipedEnoughToShowMenu());
+
+        when(row.getTranslation()).thenReturn(50f);
+        assertTrue("on left, translation is greater than min", row.isSwipedEnoughToShowMenu());
+
+        when(row.isMenuOnLeft()).thenReturn(false);
+        when(row.getTranslation()).thenReturn(-30f);
+        assertFalse("on right, translation is greater than -min", row.isSwipedEnoughToShowMenu());
+
+        when(row.getTranslation()).thenReturn(-50f);
+        assertTrue("on right, translation is less than -min", row.isSwipedEnoughToShowMenu());
+
+        when(row.isMenuVisible()).thenReturn(false);
+        when(row.getTranslation()).thenReturn(30f);
+        assertFalse("on left, translation greater than min, but not visible",
+                row.isSwipedEnoughToShowMenu());
+    }
+
+    @Test
+    public void testIsWithinSnapMenuThreshold() {
+        NotificationMenuRow row = Mockito.spy(new NotificationMenuRow((mContext)));
+        doReturn(30f).when(row).getSnapBackThreshold();
+        doReturn(50f).when(row).getDismissThreshold();
+
+        when(row.isMenuOnLeft()).thenReturn(true);
+        when(row.getTranslation()).thenReturn(40f);
+        assertTrue("When on left, translation is between min and max",
+                row.isWithinSnapMenuThreshold());
+
+        when(row.getTranslation()).thenReturn(20f);
+        assertFalse("When on left, translation is less than min",
+                row.isWithinSnapMenuThreshold());
+
+        when(row.getTranslation()).thenReturn(60f);
+        assertFalse("When on left, translation is greater than max",
+                row.isWithinSnapMenuThreshold());
+
+        when(row.isMenuOnLeft()).thenReturn(false);
+        when(row.getTranslation()).thenReturn(-40f);
+        assertTrue("When on right, translation is between -min and -max",
+                row.isWithinSnapMenuThreshold());
+
+        when(row.getTranslation()).thenReturn(-20f);
+        assertFalse("When on right, translation is greater than -min",
+                row.isWithinSnapMenuThreshold());
+
+        when(row.getTranslation()).thenReturn(-60f);
+        assertFalse("When on right, translation is less than -max",
+                row.isWithinSnapMenuThreshold());
+    }
+
+    @Test
+    public void testShouldSnapBack() {
+        NotificationMenuRow row = Mockito.spy(new NotificationMenuRow((mContext)));
+        doReturn(40f).when(row).getSnapBackThreshold();
+        when(row.isMenuVisible()).thenReturn(false);
+        when(row.isMenuOnLeft()).thenReturn(true);
+
+        when(row.getTranslation()).thenReturn(50f);
+        assertFalse("On left, translation greater than minimum target", row.shouldSnapBack());
+
+        when(row.getTranslation()).thenReturn(30f);
+        assertTrue("On left, translation less than minimum target", row.shouldSnapBack());
+
+        when(row.isMenuOnLeft()).thenReturn(false);
+        when(row.getTranslation()).thenReturn(-50f);
+        assertFalse("On right, translation less than minimum target", row.shouldSnapBack());
+
+        when(row.getTranslation()).thenReturn(-30f);
+        assertTrue("On right, translation greater than minimum target", row.shouldSnapBack());
+    }
+
+    @Test
+    public void testCanBeDismissed() {
+        NotificationMenuRow row = Mockito.spy(new NotificationMenuRow((mContext)));
+        ExpandableNotificationRow parent = mock(ExpandableNotificationRow.class);
+
+        when(row.getParent()).thenReturn(parent);
+        when(parent.canViewBeDismissed()).thenReturn(true);
+
+        assertTrue("Row can be dismissed if parent can be dismissed", row.canBeDismissed());
+
+        when(parent.canViewBeDismissed()).thenReturn(false);
+        assertFalse("Row cannot be dismissed if parent cannot be dismissed",
+                row.canBeDismissed());
+    }
+
+    @Test
+    public void testIsTowardsMenu() {
+        NotificationMenuRow row = Mockito.spy(new NotificationMenuRow((mContext)));
+        when(row.isMenuVisible()).thenReturn(true);
+        when(row.isMenuOnLeft()).thenReturn(true);
+
+        assertTrue("menu on left, movement is negative", row.isTowardsMenu(-30f));
+        assertFalse("menu on left, movement is positive", row.isTowardsMenu(30f));
+        assertTrue("menu on left, movement is 0", row.isTowardsMenu(0f));
+
+        when(row.isMenuOnLeft()).thenReturn(false);
+        assertTrue("menu on right, movement is positive", row.isTowardsMenu(30f));
+        assertFalse("menu on right, movement is negative", row.isTowardsMenu(-30f));
+        assertTrue("menu on right, movement is 0", row.isTowardsMenu(0f));
+
+        when(row.isMenuVisible()).thenReturn(false);
+        assertFalse("menu on left, movement is negative, but menu not visible",
+                row.isTowardsMenu(-30f));
+    }
+
+    @Test
+    public void onSnapBack() {
+        NotificationMenuRow row = Mockito.spy(new NotificationMenuRow((mContext)));
+        NotificationMenuRowPlugin.OnMenuEventListener listener = mock(NotificationMenuRowPlugin
+                .OnMenuEventListener.class);
+        row.setMenuClickListener(listener);
+        ExpandableNotificationRow parent = mock(ExpandableNotificationRow.class);
+        when(row.getParent()).thenReturn(parent);
+        doNothing().when(row).cancelDrag();
+
+        row.onSnapOpen();
+
+        assertTrue("before onSnapClosed, row is snapped to", row.isMenuSnapped());
+        assertFalse("before onSnapClosed, row is not snapping", row.isSnapping());
+
+        row.onSnapClosed();
+
+        assertFalse("after onSnapClosed, row is not snapped to", row.isMenuSnapped());
+        assertTrue("after onSnapClosed, row is snapping", row.isSnapping());
+    }
+
+    @Test
+    public void testOnSnap() {
+        NotificationMenuRow row = Mockito.spy(new NotificationMenuRow((mContext)));
+        when(row.isMenuOnLeft()).thenReturn(true);
+        NotificationMenuRowPlugin.OnMenuEventListener listener = mock(NotificationMenuRowPlugin
+                .OnMenuEventListener.class);
+        row.setMenuClickListener(listener);
+        ExpandableNotificationRow parent = mock(ExpandableNotificationRow.class);
+        when(row.getParent()).thenReturn(parent);
+
+        assertFalse("before onSnapOpen, row is not snapped to", row.isMenuSnapped());
+        assertFalse("before onSnapOpen, row is not snapped on left", row.isMenuSnappedOnLeft());
+
+        row.onSnapOpen();
+
+        assertTrue("after onSnapOpen, row is snapped to", row.isMenuSnapped());
+        assertTrue("after onSnapOpen, row is snapped on left", row.isMenuSnapped());
+        verify(listener, times(1)).onMenuShown(parent);
+    }
+
+    @Test
+    public void testOnDismiss() {
+        NotificationMenuRow row = Mockito.spy(new NotificationMenuRow((mContext)));
+        doNothing().when(row).cancelDrag();
+        row.onSnapOpen();
+
+        assertFalse("before onDismiss, row is not dismissing", row.isDismissing());
+        assertTrue("before onDismiss, row is showing", row.isMenuSnapped());
+
+        row.onDismiss();
+
+        verify(row, times(1)).cancelDrag();
+        assertTrue("after onDismiss, row is dismissing", row.isDismissing());
+        assertFalse("after onDismiss, row is not showing", row.isMenuSnapped());
+    }
+
+    @Test
+    public void testOnDown() {
+        NotificationMenuRow row = Mockito.spy(new NotificationMenuRow((mContext)));
+        doNothing().when(row).beginDrag();
+
+        row.onTouchStart();
+
+        verify(row, times(1)).beginDrag();
+    }
+
+    @Test
+    public void testOnUp() {
+        NotificationMenuRow row = Mockito.spy(new NotificationMenuRow((mContext)));
+        row.onTouchStart();
+
+        assertTrue("before onTouchEnd, isUserTouching is true", row.isUserTouching());
+
+        row.onTouchEnd();
+
+        assertFalse("after onTouchEnd, isUserTouching is false", row.isUserTouching());
+    }
+
+    @Test
+    public void testIsMenuVisible() {
+        NotificationMenuRow row = Mockito.spy(new NotificationMenuRow((mContext)));
+        row.setMenuAlpha(0);
+
+        assertFalse("when alpha is 0, menu is not visible", row.isMenuVisible());
+
+        row.setMenuAlpha(0.5f);
+        assertTrue("when alpha is .5, menu is visible", row.isMenuVisible());
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
index 087aa59..2728453 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.notification.stack;
 
 import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
 import android.view.NotificationHeaderView;
@@ -51,7 +50,7 @@
 
     @Test
     public void testGetMaxAllowedVisibleChildren_ambient() {
-        mGroup.setShowAmbient(true);
+        mGroup.setOnAmbient(true);
         Assert.assertEquals(mChildrenContainer.getMaxAllowedVisibleChildren(),
             NotificationChildrenContainer.NUMBER_OF_CHILDREN_WHEN_AMBIENT);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index ce0bd58..b545e61 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -19,6 +19,7 @@
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
@@ -31,6 +32,7 @@
 import android.os.IPowerManager;
 import android.os.Looper;
 import android.os.PowerManager;
+import android.service.dreams.IDreamManager;
 import android.support.test.annotation.UiThreadTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
@@ -38,7 +40,6 @@
 import com.android.systemui.ExpandHelper;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.statusbar.EmptyShadeView;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.NotificationPresenter;
@@ -90,7 +91,7 @@
     @Mock private NotificationData mNotificationData;
     @Mock private NotificationRemoteInputManager mRemoteInputManager;
     @Mock private RemoteInputController mRemoteInputController;
-    @Mock private SystemServicesProxy mSystemServicesProxy;
+    @Mock private IDreamManager mDreamManager;
     private PowerManager mPowerManager;
     private TestableNotificationEntryManager mEntryManager;
 
@@ -110,7 +111,7 @@
         mPowerManager = new PowerManager(mContext, powerManagerService,
                 Handler.createAsync(Looper.myLooper()));
 
-        mEntryManager = new TestableNotificationEntryManager(mSystemServicesProxy, mPowerManager,
+        mEntryManager = new TestableNotificationEntryManager(mDreamManager, mPowerManager,
                 mContext);
         mEntryManager.setUpForTest(mock(NotificationPresenter.class), null, null, mHeadsUpManager,
                 mNotificationData);
@@ -316,7 +317,7 @@
     private void setBarStateForTest(int state) {
         ArgumentCaptor<StatusBarStateController.StateListener> captor =
                 ArgumentCaptor.forClass(StatusBarStateController.StateListener.class);
-        verify(mBarState).addListener(captor.capture());
+        verify(mBarState, atLeastOnce()).addListener(captor.capture());
         captor.getValue().onStateChanged(state);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
new file mode 100644
index 0000000..b5f67c0
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
@@ -0,0 +1,511 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification.stack;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockitoSession;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.IPowerManager;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.service.notification.StatusBarNotification;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.MotionEvent;
+
+import com.android.systemui.SwipeHelper;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.NotificationMenuRow;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+
+/**
+ * Tests for {@link NotificationSwipeHelper}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class NotificationSwipeHelperTest extends SysuiTestCase {
+
+    private NotificationSwipeHelper mSwipeHelper;
+    private NotificationSwipeHelper.NotificationCallback mCallback;
+    private NotificationMenuRowPlugin.OnMenuEventListener mListener;
+    private View mView;
+    private MotionEvent mEvent;
+    private NotificationMenuRowPlugin mMenuRow;
+    private Handler mHandler;
+    private ExpandableNotificationRow mNotificationRow;
+    private Runnable mFalsingCheck;
+
+    @Rule public MockitoRule mockito = MockitoJUnit.rule();
+
+    @Before
+    @UiThreadTest
+    public void setUp() throws Exception {
+        mCallback = mock(NotificationSwipeHelper.NotificationCallback.class);
+        mListener = mock(NotificationMenuRowPlugin.OnMenuEventListener.class);
+        mSwipeHelper = spy(new NotificationSwipeHelper(SwipeHelper.X, mCallback, mContext, mListener));
+        mView = mock(View.class);
+        mEvent = mock(MotionEvent.class);
+        mMenuRow = mock(NotificationMenuRowPlugin.class);
+        mNotificationRow = mock(ExpandableNotificationRow.class);
+        mHandler = mock(Handler.class);
+        mFalsingCheck = mock(Runnable.class);
+    }
+
+    @Test
+    public void testSetExposedMenuView() {
+        assertEquals("intialized with null exposed menu view", null,
+                mSwipeHelper.getExposedMenuView());
+        mSwipeHelper.setExposedMenuView(mView);
+        assertEquals("swipe helper has correct exposedMenuView after setExposedMenuView to a view",
+                mView, mSwipeHelper.getExposedMenuView());
+        mSwipeHelper.setExposedMenuView(null);
+        assertEquals("swipe helper has null exposedMenuView after setExposedMenuView to null",
+                null, mSwipeHelper.getExposedMenuView());
+    }
+
+    @Test
+    public void testClearExposedMenuView() {
+        doNothing().when(mSwipeHelper).setExposedMenuView(mView);
+        mSwipeHelper.clearExposedMenuView();
+        verify(mSwipeHelper, times(1)).setExposedMenuView(null);
+    }
+
+    @Test
+    public void testGetTranslatingParentView() {
+        assertEquals("intialized with null translating parent view", null,
+                mSwipeHelper.getTranslatingParentView());
+        mSwipeHelper.setTranslatingParentView(mView);
+        assertEquals("has translating parent view after setTranslatingParentView with a view",
+                mView, mSwipeHelper.getTranslatingParentView());
+    }
+
+    @Test
+    public void testClearTranslatingParentView() {
+        doNothing().when(mSwipeHelper).setTranslatingParentView(null);
+        mSwipeHelper.clearTranslatingParentView();
+        verify(mSwipeHelper, times(1)).setTranslatingParentView(null);
+    }
+
+    @Test
+    public void testSetCurrentMenuRow() {
+        assertEquals("currentMenuRow initializes to null", null,
+                mSwipeHelper.getCurrentMenuRow());
+        mSwipeHelper.setCurrentMenuRow(mMenuRow);
+        assertEquals("currentMenuRow set correctly after setCurrentMenuRow", mMenuRow,
+                mSwipeHelper.getCurrentMenuRow());
+        mSwipeHelper.setCurrentMenuRow(null);
+        assertEquals("currentMenuRow set to null after setCurrentMenuRow to null",
+                null, mSwipeHelper.getCurrentMenuRow());
+    }
+
+    @Test
+    public void testClearCurrentMenuRow() {
+        doNothing().when(mSwipeHelper).setCurrentMenuRow(null);
+        mSwipeHelper.clearCurrentMenuRow();
+        verify(mSwipeHelper, times(1)).setCurrentMenuRow(null);
+    }
+
+    @Test
+    public void testOnDownUpdate_ExpandableNotificationRow() {
+        when(mSwipeHelper.getHandler()).thenReturn(mHandler);
+        when(mSwipeHelper.getFalsingCheck()).thenReturn(mFalsingCheck);
+        doNothing().when(mSwipeHelper).resetExposedMenuView(true, false);
+        doNothing().when(mSwipeHelper).clearCurrentMenuRow();
+        doNothing().when(mSwipeHelper).initializeRow(any());
+
+        mSwipeHelper.onDownUpdate(mNotificationRow, mEvent);
+
+        verify(mSwipeHelper, times(1)).clearCurrentMenuRow();
+        verify(mHandler, times(1)).removeCallbacks(mFalsingCheck);
+        verify(mSwipeHelper, times(1)).resetExposedMenuView(true, false);
+        verify(mSwipeHelper, times(1)).initializeRow(mNotificationRow);
+    }
+
+    @Test
+    public void testOnDownUpdate_notExpandableNotificationRow() {
+        when(mSwipeHelper.getHandler()).thenReturn(mHandler);
+        when(mSwipeHelper.getFalsingCheck()).thenReturn(mFalsingCheck);
+        doNothing().when(mSwipeHelper).resetExposedMenuView(true, false);
+        doNothing().when(mSwipeHelper).clearCurrentMenuRow();
+        doNothing().when(mSwipeHelper).initializeRow(any());
+
+        mSwipeHelper.onDownUpdate(mView, mEvent);
+
+        verify(mSwipeHelper, times(1)).clearCurrentMenuRow();
+        verify(mHandler, times(1)).removeCallbacks(mFalsingCheck);
+        verify(mSwipeHelper, times(1)).resetExposedMenuView(true, false);
+        verify(mSwipeHelper, times(0)).initializeRow(any());
+    }
+
+    @Test
+    public void testOnMoveUpdate_menuRow() {
+        when(mSwipeHelper.getCurrentMenuRow()).thenReturn(mMenuRow);
+        when(mSwipeHelper.getHandler()).thenReturn(mHandler);
+        when(mSwipeHelper.getFalsingCheck()).thenReturn(mFalsingCheck);
+
+        mSwipeHelper.onMoveUpdate(mView, mEvent, 0, 10);
+
+        verify(mHandler, times(1)).removeCallbacks(mFalsingCheck);
+        verify(mMenuRow, times(1)).onTouchMove(10);
+    }
+
+    @Test
+    public void testOnMoveUpdate_noMenuRow() {
+        when(mSwipeHelper.getHandler()).thenReturn(mHandler);
+        when(mSwipeHelper.getFalsingCheck()).thenReturn(mFalsingCheck);
+
+        mSwipeHelper.onMoveUpdate(mView, mEvent, 0, 10);
+
+        verify(mHandler, times(1)).removeCallbacks(mFalsingCheck);
+    }
+
+    @Test
+    public void testHandleUpEvent_noMenuRow() {
+        assertFalse("Menu row does not exist",
+                mSwipeHelper.handleUpEvent(mEvent, mView, 0, 0));
+    }
+
+    @Test
+    public void testHandleUpEvent_menuRow() {
+        when(mSwipeHelper.getCurrentMenuRow()).thenReturn(mMenuRow);
+        doNothing().when(mSwipeHelper).handleMenuRowSwipe(mEvent, mView, 0, mMenuRow);
+
+        assertTrue("Menu row exists",
+                mSwipeHelper.handleUpEvent(mEvent, mView, 0, 0));
+        verify(mMenuRow, times(1)).onTouchEnd();
+        verify(mSwipeHelper, times(1)).handleMenuRowSwipe(mEvent, mView, 0, mMenuRow);
+    }
+
+    @Test
+    public void testDismissChild_notExpanded() {
+        when(mCallback.isExpanded()).thenReturn(false);
+        doNothing().when(mSwipeHelper).superDismissChild(mView, 0, false);
+        doNothing().when(mSwipeHelper).handleMenuCoveredOrDismissed();
+
+        mSwipeHelper.dismissChild(mView, 0, false);
+
+        verify(mSwipeHelper, times(1)).superDismissChild(mView, 0, false);
+        verify(mCallback, times(0)).handleChildViewDismissed(mView);
+        verify(mCallback, times(1)).onDismiss();
+        verify(mSwipeHelper, times(1)).handleMenuCoveredOrDismissed();
+    }
+
+    @Test
+    public void testSnapchild_targetIsZero() {
+        doNothing().when(mSwipeHelper).superSnapChild(mView, 0, 0);
+        mSwipeHelper.snapChild(mView, 0, 0);
+
+        verify(mCallback, times(1)).onDragCancelled(mView);
+        verify(mSwipeHelper, times(1)).superSnapChild(mView, 0, 0);
+        verify(mSwipeHelper, times(1)).handleMenuCoveredOrDismissed();
+    }
+
+
+    @Test
+    public void testSnapchild_targetNotZero() {
+        doNothing().when(mSwipeHelper).superSnapChild(mView, 10, 0);
+        mSwipeHelper.snapChild(mView, 10, 0);
+
+        verify(mCallback, times(1)).onDragCancelled(mView);
+        verify(mSwipeHelper, times(1)).superSnapChild(mView, 10, 0);
+        verify(mSwipeHelper, times(0)).handleMenuCoveredOrDismissed();
+    }
+
+    @Test
+    public void testSnooze() {
+        StatusBarNotification sbn = mock(StatusBarNotification.class);
+        SnoozeOption snoozeOption = mock(SnoozeOption.class);
+        mSwipeHelper.snooze(sbn, snoozeOption);
+        verify(mCallback, times(1)).onSnooze(sbn, snoozeOption);
+    }
+
+    @Test
+    public void testGetViewTranslationAnimator_notExpandableNotificationRow() {
+        Animator animator = mock(Animator.class);
+        AnimatorUpdateListener listener = mock(AnimatorUpdateListener.class);
+        doReturn(animator).when(mSwipeHelper).superGetViewTranslationAnimator(mView, 0, listener);
+
+        assertEquals("returns the correct animator from super", animator,
+                mSwipeHelper.getViewTranslationAnimator(mView, 0, listener));
+
+        verify(mSwipeHelper, times(1)).superGetViewTranslationAnimator(mView, 0, listener);
+    }
+
+    @Test
+    public void testGetViewTranslationAnimator_expandableNotificationRow() {
+        Animator animator = mock(Animator.class);
+        AnimatorUpdateListener listener = mock(AnimatorUpdateListener.class);
+        doReturn(animator).when(mNotificationRow).getTranslateViewAnimator(0, listener);
+
+        assertEquals("returns the correct animator from super when view is an ENR", animator,
+                mSwipeHelper.getViewTranslationAnimator(mNotificationRow, 0, listener));
+
+        verify(mNotificationRow, times(1)).getTranslateViewAnimator(0, listener);
+    }
+
+    @Test
+    public void testSetTranslation() {
+        mSwipeHelper.setTranslation(mNotificationRow, 0);
+        verify(mNotificationRow, times(1)).setTranslation(0);
+    }
+
+    @Test
+    public void testGetTranslation() {
+        doReturn(30f).when(mNotificationRow).getTranslation();
+
+        assertEquals("Returns getTranslation for the ENR",
+                mSwipeHelper.getTranslation(mNotificationRow), 30f);
+
+        verify(mNotificationRow, times(1)).getTranslation();
+    }
+
+    @Test
+    public void testDismiss() {
+        doNothing().when(mSwipeHelper).dismissChild(mView, 0, true);
+        doReturn(false).when(mSwipeHelper).swipedFastEnough();
+
+        mSwipeHelper.dismiss(mView, 0);
+
+        verify(mSwipeHelper, times(1)).swipedFastEnough();
+        verify(mSwipeHelper, times(1)).dismissChild(mView, 0, true);
+    }
+
+    @Test
+    public void testSnapOpen() {
+        doNothing().when(mSwipeHelper).snapChild(mView, 30, 0);
+
+        mSwipeHelper.snapOpen(mView, 30, 0);
+
+        verify(mSwipeHelper, times(1)).snapChild(mView, 30, 0);
+    }
+
+    @Test
+    public void testSnapClosed() {
+        doNothing().when(mSwipeHelper).snapChild(mView, 0, 0);
+
+        mSwipeHelper.snapClosed(mView, 0);
+
+        verify(mSwipeHelper, times(1)).snapChild(mView, 0, 0);
+    }
+
+    @Test
+    public void testGetMinDismissVelocity() {
+        doReturn(30f).when(mSwipeHelper).getEscapeVelocity();
+
+        assertEquals("Returns getEscapeVelocity", 30f, mSwipeHelper.getMinDismissVelocity());
+    }
+
+    @Test
+    public void onMenuShown_noAntiFalsing() {
+        doNothing().when(mSwipeHelper).setExposedMenuView(mView);
+        doReturn(mView).when(mSwipeHelper).getTranslatingParentView();
+        doReturn(mHandler).when(mSwipeHelper).getHandler();
+        doReturn(false).when(mCallback).isAntiFalsingNeeded();
+        doReturn(mFalsingCheck).when(mSwipeHelper).getFalsingCheck();
+
+        mSwipeHelper.onMenuShown(mView);
+
+        verify(mSwipeHelper, times(1)).setExposedMenuView(mView);
+        verify(mCallback, times(1)).onDragCancelled(mView);
+        verify(mCallback, times(1)).isAntiFalsingNeeded();
+
+        verify(mHandler, times(0)).removeCallbacks(mFalsingCheck);
+        verify(mHandler, times(0)).postDelayed(mFalsingCheck, mSwipeHelper.COVER_MENU_DELAY);
+    }
+
+    @Test
+    public void onMenuShown_antiFalsing() {
+        doNothing().when(mSwipeHelper).setExposedMenuView(mView);
+        doReturn(mView).when(mSwipeHelper).getTranslatingParentView();
+        doReturn(mHandler).when(mSwipeHelper).getHandler();
+        doReturn(true).when(mCallback).isAntiFalsingNeeded();
+        doReturn(mFalsingCheck).when(mSwipeHelper).getFalsingCheck();
+
+        mSwipeHelper.onMenuShown(mView);
+
+        verify(mSwipeHelper, times(1)).setExposedMenuView(mView);
+        verify(mCallback, times(1)).onDragCancelled(mView);
+        verify(mCallback, times(1)).isAntiFalsingNeeded();
+
+        verify(mHandler, times(1)).removeCallbacks(mFalsingCheck);
+        verify(mHandler, times(1)).postDelayed(mFalsingCheck, mSwipeHelper.COVER_MENU_DELAY);
+    }
+
+    @Test
+    public void testResetExposedMenuView_noReset() {
+        doReturn(false).when(mSwipeHelper).shouldResetMenu(false);
+        doNothing().when(mSwipeHelper).clearExposedMenuView();
+
+        mSwipeHelper.resetExposedMenuView(false, false);
+
+        verify(mSwipeHelper, times(1)).shouldResetMenu(false);
+
+        // should not clear exposed menu row
+        verify(mSwipeHelper, times(0)).clearExposedMenuView();
+    }
+
+    @Test
+    public void testResetExposedMenuView_animate() {
+        Animator animator = mock(Animator.class);
+
+        doReturn(true).when(mSwipeHelper).shouldResetMenu(false);
+        doReturn(mNotificationRow).when(mSwipeHelper).getExposedMenuView();
+        doReturn(false).when(mNotificationRow).isRemoved();
+        doReturn(animator).when(mSwipeHelper).getViewTranslationAnimator(mNotificationRow, 0, null);
+        doNothing().when(mSwipeHelper).clearExposedMenuView();
+
+        mSwipeHelper.resetExposedMenuView(true, false);
+
+        verify(mSwipeHelper, times(1)).shouldResetMenu(false);
+
+        // should retrieve and start animator
+        verify(mSwipeHelper, times(1)).getViewTranslationAnimator(mNotificationRow, 0, null);
+        verify(animator, times(1)).start();
+
+        // should not reset translation on row directly
+        verify(mNotificationRow, times(0)).resetTranslation();
+
+        // should clear exposed menu row
+        verify(mSwipeHelper, times(1)).clearExposedMenuView();
+    }
+
+
+    @Test
+    public void testResetExposedMenuView_noAnimate() {
+        Animator animator = mock(Animator.class);
+
+        doReturn(true).when(mSwipeHelper).shouldResetMenu(false);
+        doReturn(mNotificationRow).when(mSwipeHelper).getExposedMenuView();
+        doReturn(false).when(mNotificationRow).isRemoved();
+        doReturn(animator).when(mSwipeHelper).getViewTranslationAnimator(mNotificationRow, 0, null);
+        doNothing().when(mSwipeHelper).clearExposedMenuView();
+
+        mSwipeHelper.resetExposedMenuView(false, false);
+
+        verify(mSwipeHelper, times(1)).shouldResetMenu(false);
+
+        // should not retrieve and start animator
+        verify(mSwipeHelper, times(0)).getViewTranslationAnimator(mNotificationRow, 0, null);
+        verify(animator, times(0)).start();
+
+        // should reset translation on row directly
+        verify(mNotificationRow, times(1)).resetTranslation();
+
+        // should clear exposed menu row
+        verify(mSwipeHelper, times(1)).clearExposedMenuView();
+    }
+
+    @Test
+    public void testIsTouchInView() {
+        assertEquals("returns false when view is null", false,
+                NotificationSwipeHelper.isTouchInView(mEvent, null));
+
+        doReturn(5f).when(mEvent).getRawX();
+        doReturn(10f).when(mEvent).getRawY();
+
+        doReturn(20).when(mView).getWidth();
+        doReturn(20).when(mView).getHeight();
+
+        Answer answer = (Answer) invocation -> {
+            int[] arr = invocation.getArgument(0);
+            arr[0] = 0;
+            arr[1] = 0;
+            return null;
+        };
+        doAnswer(answer).when(mView).getLocationOnScreen(any());
+
+        assertTrue("Touch is within the view",
+                mSwipeHelper.isTouchInView(mEvent, mView));
+
+        doReturn(50f).when(mEvent).getRawX();
+
+        assertFalse("Touch is not within the view",
+                mSwipeHelper.isTouchInView(mEvent, mView));
+    }
+
+    @Test
+    public void testIsTouchInView_expandable() {
+        assertEquals("returns false when view is null", false,
+                NotificationSwipeHelper.isTouchInView(mEvent, null));
+
+        doReturn(5f).when(mEvent).getRawX();
+        doReturn(10f).when(mEvent).getRawY();
+
+        doReturn(20).when(mNotificationRow).getWidth();
+        doReturn(20).when(mNotificationRow).getActualHeight();
+
+        Answer answer = (Answer) invocation -> {
+            int[] arr = invocation.getArgument(0);
+            arr[0] = 0;
+            arr[1] = 0;
+            return null;
+        };
+        doAnswer(answer).when(mNotificationRow).getLocationOnScreen(any());
+
+        assertTrue("Touch is within the view",
+                mSwipeHelper.isTouchInView(mEvent, mNotificationRow));
+
+        doReturn(50f).when(mEvent).getRawX();
+
+        assertFalse("Touch is not within the view",
+                mSwipeHelper.isTouchInView(mEvent, mNotificationRow));
+    }
+}
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 a81d17f..1070795 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
@@ -82,28 +82,26 @@
         // Remove should succeed because the notification is swiped out
         mHeadsUpManager.removeNotification(mEntry.key, false /* releaseImmediately */);
 
-        assertFalse(mHeadsUpManager.contains(mEntry.key));
+        assertFalse(mHeadsUpManager.isAlerting(mEntry.key));
     }
 
     @Test
-    public void testShouldExtendLifetime_swipedOut() {
+    public void testCanRemoveImmediately_swipedOut() {
         mHeadsUpManager.showNotification(mEntry);
         mHeadsUpManager.addSwipedOutNotification(mEntry.key);
 
-        // Notification is swiped so its lifetime should not be extended even if it hasn't been
-        // shown long enough
-        assertFalse(mHeadsUpManager.shouldExtendLifetime(mEntry));
+        // Notification is swiped so it can be immediately removed.
+        assertTrue(mHeadsUpManager.canRemoveImmediately(mEntry.key));
     }
 
     @Test
-    public void testShouldExtendLifetime_notTopEntry() {
+    public void testCanRemoveImmediately_notTopEntry() {
         NotificationData.Entry laterEntry = new NotificationData.Entry(createNewNotification(1));
         laterEntry.row = mRow;
         mHeadsUpManager.showNotification(mEntry);
         mHeadsUpManager.showNotification(laterEntry);
 
-        // Notification is "behind" a higher priority notification so we have no reason to keep
-        // its lifetime extended
-        assertFalse(mHeadsUpManager.shouldExtendLifetime(mEntry));
+        // Notification is "behind" a higher priority notification so we can remove it immediately.
+        assertTrue(mHeadsUpManager.canRemoveImmediately(mEntry.key));
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java
new file mode 100644
index 0000000..c792459
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.doReturn;
+
+import android.graphics.drawable.Drawable;
+import android.support.test.filters.SmallTest;
+import android.view.View;
+import com.android.systemui.statusbar.policy.KeyButtonDrawable;
+import com.android.systemui.SysuiTestCase;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.support.test.runner.AndroidJUnit4;
+
+/** atest NavigationBarContextTest */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class NavigationBarContextTest extends SysuiTestCase {
+    private static final int GROUP_ID = 1;
+    private static final int BUTTON_0_ID = GROUP_ID + 1;
+    private static final int BUTTON_1_ID = GROUP_ID + 2;
+    private static final int BUTTON_2_ID = GROUP_ID + 3;
+
+    private static final float TEST_DARK_INTENSITY = 0.6f;
+    private static final float DARK_INTENSITY_ERR = 0.0002f;
+    private static final int ICON_RES_ID = 1;
+
+    private ContextualButtonGroup mGroup;
+    private ContextualButton mBtn0;
+    private ContextualButton mBtn1;
+    private ContextualButton mBtn2;
+
+    @Before
+    public void setup() {
+        mGroup = new ContextualButtonGroup(GROUP_ID);
+        mBtn0 = new ContextualButton(BUTTON_0_ID, ICON_RES_ID);
+        mBtn1 = new ContextualButton(BUTTON_1_ID, ICON_RES_ID);
+        mBtn2 = new ContextualButton(BUTTON_2_ID, ICON_RES_ID);
+
+        // Order of adding buttons to group determines the priority, ascending priority order
+        mGroup.addButton(mBtn0);
+        mGroup.addButton(mBtn1);
+        mGroup.addButton(mBtn2);
+    }
+
+    @Test
+    public void testAddGetContextButtons() throws Exception {
+        assertEquals(mBtn0, mGroup.getContextButton(BUTTON_0_ID));
+        assertEquals(mBtn1, mGroup.getContextButton(BUTTON_1_ID));
+        assertEquals(mBtn2, mGroup.getContextButton(BUTTON_2_ID));
+    }
+
+    @Test
+    public void testSetButtonVisibility() throws Exception {
+        assertFalse("By default the group should be invisible.", mGroup.isVisible());
+
+        // Set button 1 to be visible, make sure it is the only visible button
+        showButton(mBtn1);
+        assertFalse(mBtn0.isVisible());
+        assertTrue(mBtn1.isVisible());
+        assertFalse(mBtn2.isVisible());
+
+        // Hide button 1 and make sure the group is also invisible
+        assertNotEquals(mGroup.setButtonVisiblity(BUTTON_1_ID, false /* visible */), View.VISIBLE);
+        assertFalse("No buttons are visible, group should also be hidden", mGroup.isVisible());
+        assertNull("No buttons should be visible", mGroup.getVisibleContextButton());
+    }
+
+    @Test(expected = RuntimeException.class)
+    public void testSetButtonVisibilityUnaddedButton() throws Exception {
+        int id = mBtn2.getId() + 1;
+        mGroup.setButtonVisiblity(id, true /* visible */);
+        fail("Did not throw when setting a button with an invalid id");
+    }
+
+    @Test
+    public void testSetHigherPriorityButton() throws Exception {
+        // Show button 0
+        showButton(mBtn0);
+
+        // Show button 1
+        showButton(mBtn1);
+        assertTrue("Button 0 should be visible behind",
+                mGroup.isButtonVisibleWithinGroup(mBtn0.getId()));
+
+        // Show button 2
+        showButton(mBtn2);
+        assertTrue("Button 1 should be visible behind",
+                mGroup.isButtonVisibleWithinGroup(mBtn1.getId()));
+        assertTrue(mGroup.isButtonVisibleWithinGroup(mBtn0.getId()));
+        assertTrue(mGroup.isButtonVisibleWithinGroup(mBtn1.getId()));
+        assertTrue(mGroup.isButtonVisibleWithinGroup(mBtn2.getId()));
+
+        // Hide button 2
+        assertNotEquals(mGroup.setButtonVisiblity(BUTTON_2_ID, false /* visible */), View.VISIBLE);
+        assertEquals("Hiding button 2 should show button 1", mBtn1,
+                mGroup.getVisibleContextButton());
+
+        // Hide button 1
+        assertNotEquals(mGroup.setButtonVisiblity(BUTTON_1_ID, false /* visible */), View.VISIBLE);
+        assertEquals("Hiding button 1 should show button 0", mBtn0,
+                mGroup.getVisibleContextButton());
+
+        // Hide button 0, all buttons are now invisible
+        assertNotEquals(mGroup.setButtonVisiblity(BUTTON_0_ID, false /* visible */), View.VISIBLE);
+        assertFalse("No buttons are visible, group should also be invisible", mGroup.isVisible());
+        assertNull(mGroup.getVisibleContextButton());
+        assertFalse(mGroup.isButtonVisibleWithinGroup(mBtn0.getId()));
+        assertFalse(mGroup.isButtonVisibleWithinGroup(mBtn1.getId()));
+        assertFalse(mGroup.isButtonVisibleWithinGroup(mBtn2.getId()));
+    }
+
+    @Test
+    public void testSetLowerPriorityButton() throws Exception {
+        // Show button 2
+        showButton(mBtn2);
+
+        // Show button 1
+        assertNotEquals(mGroup.setButtonVisiblity(BUTTON_1_ID, true /* visible */), View.VISIBLE);
+        assertTrue("Showing button 1 lower priority should be hidden but visible underneath",
+                mGroup.isButtonVisibleWithinGroup(BUTTON_1_ID));
+        assertFalse(mBtn0.isVisible());
+        assertFalse(mBtn1.isVisible());
+        assertTrue(mBtn2.isVisible());
+
+        // Hide button 1
+        assertNotEquals(mGroup.setButtonVisiblity(BUTTON_1_ID, false /* visible */), View.VISIBLE);
+        assertFalse("Hiding button 1 with lower priority hides itself underneath",
+                mGroup.isButtonVisibleWithinGroup(BUTTON_1_ID));
+        assertTrue("A button still visible, group should also be visible", mGroup.isVisible());
+        assertEquals(mBtn2, mGroup.getVisibleContextButton());
+    }
+
+    @Test
+    public void testSetSamePriorityButton() throws Exception {
+        // Show button 1
+        showButton(mBtn1);
+
+        // Show button 1 again
+        showButton(mBtn1);
+
+        // The original button should still be visible
+        assertEquals(mBtn1, mGroup.getVisibleContextButton());
+        assertFalse(mGroup.isButtonVisibleWithinGroup(mBtn0.getId()));
+        assertFalse(mGroup.isButtonVisibleWithinGroup(mBtn2.getId()));
+    }
+
+    @Test
+    public void testUpdateIconsDarkIntensity() throws Exception {
+        final int unusedColor = 0;
+        final Drawable d = mock(Drawable.class);
+        final ContextualButton button = spy(mBtn0);
+        final KeyButtonDrawable kbd1 = spy(new KeyButtonDrawable(d, unusedColor, unusedColor));
+        final KeyButtonDrawable kbd2 = spy(new KeyButtonDrawable(d, unusedColor, unusedColor));
+        kbd1.setDarkIntensity(TEST_DARK_INTENSITY);
+        kbd2.setDarkIntensity(0f);
+
+        // Update icon returns the drawable intensity to half
+        doReturn(kbd1).when(button).getNewDrawable();
+        button.updateIcon();
+        assertEquals(TEST_DARK_INTENSITY, kbd1.getDarkIntensity(), DARK_INTENSITY_ERR);
+
+        // Return old dark intensity on new drawable after update icon
+        doReturn(kbd2).when(button).getNewDrawable();
+        button.updateIcon();
+        assertEquals(TEST_DARK_INTENSITY, kbd2.getDarkIntensity(), DARK_INTENSITY_ERR);
+    }
+
+    private void showButton(ContextualButton button) {
+        assertEquals(View.VISIBLE, mGroup.setButtonVisiblity(button.getId(), true /* visible */));
+        assertTrue("After set a button visible, group should also be visible", mGroup.isVisible());
+        assertEquals(button, mGroup.getVisibleContextButton());
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NearestTouchFrameTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NearestTouchFrameTest.java
index 2423e14..667a508 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NearestTouchFrameTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NearestTouchFrameTest.java
@@ -171,23 +171,6 @@
         ev.recycle();
     }
 
-    @Test
-    public void testFurtherSelectedWhenCloserNotFocusable() {
-        View closer = mockViewAt(0, 0, 10, 10);
-        View further = mockViewAt(20, 0, 10, 10);
-        closer.setFocusable(false);
-
-        mNearestTouchFrame.addView(closer);
-        mNearestTouchFrame.addView(further);
-        mNearestTouchFrame.onMeasure(0, 0);
-
-        MotionEvent ev = MotionEvent.obtain(0, 0, 0,
-                12 /* x */, 5 /* y */, 0);
-        mNearestTouchFrame.onTouchEvent(ev);
-        verify(further).onTouchEvent(eq(ev));
-        ev.recycle();
-    }
-
     private View mockViewAt(int x, int y, int width, int height) {
         View v = spy(new View(mContext));
         doAnswer(invocation -> {
@@ -204,7 +187,6 @@
         v.setRight(width);
         v.setTop(0);
         v.setBottom(height);
-        v.setFocusable(true);
         return v;
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java
new file mode 100644
index 0000000..464f74b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
+
+import android.app.ActivityManager;
+import android.app.Notification;
+import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.AmbientPulseManager;
+import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.phone.NotificationGroupManager.OnGroupChangeListener;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class NotificationGroupManagerTest extends SysuiTestCase {
+    @Rule
+    public MockitoRule rule = MockitoJUnit.rule();
+
+    private static final String TEST_CHANNEL_ID = "test_channel";
+    private static final String TEST_GROUP_ID = "test_group";
+    private static final String TEST_PACKAGE_NAME = "test_pkg";
+    private NotificationGroupManager mGroupManager;
+    private int mId = 0;
+
+    @Mock HeadsUpManager mHeadsUpManager;
+    @Mock AmbientPulseManager mAmbientPulseManager;
+
+    @Before
+    public void setup() {
+        mDependency.injectTestDependency(AmbientPulseManager.class, mAmbientPulseManager);
+
+        initializeGroupManager();
+    }
+
+    private void initializeGroupManager() {
+        mGroupManager = new NotificationGroupManager();
+        mGroupManager.setHeadsUpManager(mHeadsUpManager);
+        mGroupManager.setOnGroupChangeListener(mock(OnGroupChangeListener.class));
+    }
+
+    @Test
+    public void testIsOnlyChildInGroup() {
+        NotificationData.Entry childEntry = createChildNotification();
+        NotificationData.Entry summaryEntry = createSummaryNotification();
+
+        mGroupManager.onEntryAdded(summaryEntry);
+        mGroupManager.onEntryAdded(childEntry);
+
+        assertTrue(mGroupManager.isOnlyChildInGroup(childEntry.notification));
+    }
+
+    @Test
+    public void testIsChildInGroupWithSummary() {
+        NotificationData.Entry childEntry = createChildNotification();
+        NotificationData.Entry summaryEntry = createSummaryNotification();
+
+        mGroupManager.onEntryAdded(summaryEntry);
+        mGroupManager.onEntryAdded(childEntry);
+        mGroupManager.onEntryAdded(createChildNotification());
+
+        assertTrue(mGroupManager.isChildInGroupWithSummary(childEntry.notification));
+    }
+
+    @Test
+    public void testIsSummaryOfGroupWithChildren() {
+        NotificationData.Entry childEntry = createChildNotification();
+        NotificationData.Entry summaryEntry = createSummaryNotification();
+
+        mGroupManager.onEntryAdded(summaryEntry);
+        mGroupManager.onEntryAdded(childEntry);
+        mGroupManager.onEntryAdded(createChildNotification());
+
+        assertTrue(mGroupManager.isSummaryOfGroup(summaryEntry.notification));
+        assertEquals(summaryEntry.row, mGroupManager.getGroupSummary(childEntry.notification));
+    }
+
+    @Test
+    public void testRemoveChildFromGroupWithSummary() {
+        NotificationData.Entry childEntry = createChildNotification();
+        NotificationData.Entry summaryEntry = createSummaryNotification();
+        mGroupManager.onEntryAdded(summaryEntry);
+        mGroupManager.onEntryAdded(childEntry);
+        mGroupManager.onEntryAdded(createChildNotification());
+
+        mGroupManager.onEntryRemoved(childEntry);
+
+        assertFalse(mGroupManager.isChildInGroupWithSummary(childEntry.notification));
+    }
+
+    @Test
+    public void testRemoveSummaryFromGroupWithSummary() {
+        NotificationData.Entry childEntry = createChildNotification();
+        NotificationData.Entry summaryEntry = createSummaryNotification();
+        mGroupManager.onEntryAdded(summaryEntry);
+        mGroupManager.onEntryAdded(childEntry);
+        mGroupManager.onEntryAdded(createChildNotification());
+
+        mGroupManager.onEntryRemoved(summaryEntry);
+
+        assertNull(mGroupManager.getGroupSummary(childEntry.notification));
+        assertFalse(mGroupManager.isSummaryOfGroup(summaryEntry.notification));
+    }
+
+    @Test
+    public void testHeadsUpEntryIsIsolated() {
+        NotificationData.Entry childEntry = createChildNotification();
+        NotificationData.Entry summaryEntry = createSummaryNotification();
+        mGroupManager.onEntryAdded(summaryEntry);
+        mGroupManager.onEntryAdded(childEntry);
+        mGroupManager.onEntryAdded(createChildNotification());
+        when(mHeadsUpManager.isAlerting(childEntry.key)).thenReturn(true);
+
+        mGroupManager.onHeadsUpStateChanged(childEntry, true);
+
+        // Child entries that are heads upped should be considered separate groups visually even if
+        // they are the same group logically
+        assertEquals(childEntry.row, mGroupManager.getGroupSummary(childEntry.notification));
+        assertEquals(summaryEntry.row,
+                mGroupManager.getLogicalGroupSummary(childEntry.notification));
+    }
+
+    @Test
+    public void testAmbientPulseEntryIsIsolated() {
+        mGroupManager.setDozing(true);
+        NotificationData.Entry childEntry = createChildNotification();
+        NotificationData.Entry summaryEntry = createSummaryNotification();
+        mGroupManager.onEntryAdded(summaryEntry);
+        mGroupManager.onEntryAdded(childEntry);
+        mGroupManager.onEntryAdded(createChildNotification());
+        when(mAmbientPulseManager.isAlerting(childEntry.key)).thenReturn(true);
+
+        mGroupManager.onAmbientStateChanged(childEntry, true);
+
+        // Child entries that are heads upped should be considered separate groups visually even if
+        // they are the same group logically
+        assertEquals(childEntry.row, mGroupManager.getGroupSummary(childEntry.notification));
+        assertEquals(summaryEntry.row,
+                mGroupManager.getLogicalGroupSummary(childEntry.notification));
+    }
+
+    @Test
+    public void testSuppressedSummaryHeadsUpTransfersToChild() {
+        NotificationData.Entry summaryEntry = createSummaryNotification();
+        when(mHeadsUpManager.isAlerting(summaryEntry.key)).thenReturn(true);
+        NotificationData.Entry childEntry = createChildNotification();
+
+        // Summary will be suppressed because there is only one child.
+        mGroupManager.onEntryAdded(summaryEntry);
+        mGroupManager.onEntryAdded(childEntry);
+
+        // A suppressed summary should transfer its heads up state to the child.
+        verify(mHeadsUpManager, never()).showNotification(summaryEntry);
+        verify(mHeadsUpManager).showNotification(childEntry);
+    }
+
+    @Test
+    public void testSuppressedSummaryHeadsUpTransfersToChildButBackAgain() {
+        mHeadsUpManager = new HeadsUpManager(mContext) {};
+        mGroupManager.setHeadsUpManager(mHeadsUpManager);
+        NotificationData.Entry summaryEntry =
+                createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
+        NotificationData.Entry childEntry =
+                createChildNotification(Notification.GROUP_ALERT_SUMMARY);
+        NotificationData.Entry childEntry2 =
+                createChildNotification(Notification.GROUP_ALERT_SUMMARY);
+        mHeadsUpManager.showNotification(summaryEntry);
+        // Trigger a transfer of heads up state from summary to child.
+        mGroupManager.onEntryAdded(summaryEntry);
+        mGroupManager.onEntryAdded(childEntry);
+
+        // Add second child notification so that summary is no longer suppressed.
+        mGroupManager.onEntryAdded(childEntry2);
+
+        // The heads up state should transfer back to the summary as there is now more than one
+        // child and the summary should no longer be suppressed.
+        assertTrue(mHeadsUpManager.isAlerting(summaryEntry.key));
+        assertFalse(mHeadsUpManager.isAlerting(childEntry.key));
+    }
+
+    @Test
+    public void testSuppressedSummaryAmbientPulseTransfersToChild() {
+        mGroupManager.setDozing(true);
+        NotificationData.Entry summaryEntry = createSummaryNotification();
+        when(mAmbientPulseManager.isAlerting(summaryEntry.key)).thenReturn(true);
+        NotificationData.Entry childEntry = createChildNotification();
+
+        // Summary will be suppressed because there is only one child.
+        mGroupManager.onEntryAdded(summaryEntry);
+        mGroupManager.onEntryAdded(childEntry);
+
+        // A suppressed summary should transfer its ambient state to the child.
+        verify(mAmbientPulseManager, never()).showNotification(summaryEntry);
+        verify(mAmbientPulseManager).showNotification(childEntry);
+    }
+
+    @Test
+    public void testSuppressedSummaryAmbientPulseTransfersToChildButBackAgain() {
+        mGroupManager.setDozing(true);
+        mAmbientPulseManager = new AmbientPulseManager(mContext);
+        mDependency.injectTestDependency(AmbientPulseManager.class, mAmbientPulseManager);
+        initializeGroupManager();
+        NotificationData.Entry summaryEntry =
+                createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
+        NotificationData.Entry childEntry =
+                createChildNotification(Notification.GROUP_ALERT_SUMMARY);
+        NotificationData.Entry childEntry2 =
+                createChildNotification(Notification.GROUP_ALERT_SUMMARY);
+        mAmbientPulseManager.showNotification(summaryEntry);
+        // Trigger a transfer of ambient state from summary to child.
+        mGroupManager.onEntryAdded(summaryEntry);
+        mGroupManager.onEntryAdded(childEntry);
+
+        // Add second child notification so that summary is no longer suppressed.
+        mGroupManager.onEntryAdded(childEntry2);
+
+        // The ambient state should transfer back to the summary as there is now more than one
+        // child and the summary should no longer be suppressed.
+        assertTrue(mAmbientPulseManager.isAlerting(summaryEntry.key));
+        assertFalse(mAmbientPulseManager.isAlerting(childEntry.key));
+    }
+
+    private NotificationData.Entry createSummaryNotification() {
+        return createSummaryNotification(Notification.GROUP_ALERT_ALL);
+    }
+
+    private NotificationData.Entry createSummaryNotification(int groupAlertBehavior) {
+        return createEntry(true, groupAlertBehavior);
+    }
+
+    private NotificationData.Entry createChildNotification() {
+        return createChildNotification(Notification.GROUP_ALERT_ALL);
+    }
+
+    private NotificationData.Entry createChildNotification(int groupAlertBehavior) {
+        return createEntry(false, groupAlertBehavior);
+    }
+
+    private NotificationData.Entry createEntry(boolean isSummary, int groupAlertBehavior) {
+        Notification notif = new Notification.Builder(mContext, TEST_CHANNEL_ID)
+                .setContentTitle("Title")
+                .setSmallIcon(R.drawable.ic_person)
+                .setGroupAlertBehavior(groupAlertBehavior)
+                .setGroupSummary(isSummary)
+                .setGroup(TEST_GROUP_ID)
+                .build();
+        StatusBarNotification sbn = new StatusBarNotification(
+                TEST_PACKAGE_NAME /* pkg */,
+                TEST_PACKAGE_NAME,
+                mId++,
+                null /* tag */,
+                0, /* uid */
+                0 /* initialPid */,
+                notif,
+                new UserHandle(ActivityManager.getCurrentUser()),
+                null /* overrideGroupKey */,
+                0 /* postTime */);
+        NotificationData.Entry entry = new NotificationData.Entry(sbn);
+        ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
+        entry.row = row;
+        when(row.getEntry()).thenReturn(entry);
+        when(row.getStatusBarNotification()).thenReturn(sbn);
+        return entry;
+    }
+}
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 cbba251..da93327 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
@@ -50,6 +50,7 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.service.dreams.IDreamManager;
 import android.service.notification.StatusBarNotification;
 import android.support.test.filters.SmallTest;
 import android.support.test.metricshelper.MetricsAsserts;
@@ -119,9 +120,9 @@
     @Mock private KeyguardIndicationController mKeyguardIndicationController;
     @Mock private NotificationStackScrollLayout mStackScroller;
     @Mock private HeadsUpManagerPhone mHeadsUpManager;
-    @Mock private SystemServicesProxy mSystemServicesProxy;
     @Mock private NotificationPanelView mNotificationPanelView;
     @Mock private IStatusBarService mBarService;
+    @Mock private IDreamManager mDreamManager;
     @Mock private ScrimController mScrimController;
     @Mock private ArrayList<Entry> mNotificationList;
     @Mock private BiometricUnlockController mBiometricUnlockController;
@@ -194,8 +195,7 @@
             return null;
         }).when(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(any());
 
-        mEntryManager = new TestableNotificationEntryManager(mSystemServicesProxy, mPowerManager,
-                mContext);
+        mEntryManager = new TestableNotificationEntryManager(mDreamManager, mPowerManager, mContext);
         when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
         mStatusBar = new TestableStatusBar(mStatusBarKeyguardViewManager, mUnlockMethodCache,
                 mKeyguardIndicationController, mStackScroller, mHeadsUpManager,
@@ -358,12 +358,12 @@
     }
 
     @Test
-    public void testShouldPeek_nonSuppressedGroupSummary() {
+    public void testShouldHeadsUp_nonSuppressedGroupSummary() throws Exception {
         when(mPowerManager.isScreenOn()).thenReturn(true);
         when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
         when(mNotificationData.shouldSuppressStatusBar(any())).thenReturn(false);
         when(mNotificationData.shouldFilterOut(any())).thenReturn(false);
-        when(mSystemServicesProxy.isDreaming()).thenReturn(false);
+        when(mDreamManager.isDreaming()).thenReturn(false);
         when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);
 
         Notification n = new Notification.Builder(getContext(), "a")
@@ -375,16 +375,16 @@
                 UserHandle.of(0), null, 0);
         NotificationData.Entry entry = new NotificationData.Entry(sbn);
 
-        assertTrue(mEntryManager.shouldPeek(entry, sbn));
+        assertTrue(mEntryManager.shouldHeadsUp(entry));
     }
 
     @Test
-    public void testShouldPeek_suppressedGroupSummary() {
+    public void testShouldHeadsUp_suppressedGroupSummary() throws Exception {
         when(mPowerManager.isScreenOn()).thenReturn(true);
         when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
         when(mNotificationData.shouldSuppressStatusBar(any())).thenReturn(false);
         when(mNotificationData.shouldFilterOut(any())).thenReturn(false);
-        when(mSystemServicesProxy.isDreaming()).thenReturn(false);
+        when(mDreamManager.isDreaming()).thenReturn(false);
         when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);
 
         Notification n = new Notification.Builder(getContext(), "a")
@@ -396,15 +396,15 @@
                 UserHandle.of(0), null, 0);
         NotificationData.Entry entry = new NotificationData.Entry(sbn);
 
-        assertFalse(mEntryManager.shouldPeek(entry, sbn));
+        assertFalse(mEntryManager.shouldHeadsUp(entry));
     }
 
     @Test
-    public void testShouldPeek_suppressedPeek() {
+    public void testShouldHeadsUp_suppressedHeadsUp() throws Exception {
         when(mPowerManager.isScreenOn()).thenReturn(true);
         when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
         when(mNotificationData.shouldFilterOut(any())).thenReturn(false);
-        when(mSystemServicesProxy.isDreaming()).thenReturn(false);
+        when(mDreamManager.isDreaming()).thenReturn(false);
         when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);
 
         when(mNotificationData.shouldSuppressPeek(any())).thenReturn(true);
@@ -414,15 +414,15 @@
                 UserHandle.of(0), null, 0);
         NotificationData.Entry entry = new NotificationData.Entry(sbn);
 
-        assertFalse(mEntryManager.shouldPeek(entry, sbn));
+        assertFalse(mEntryManager.shouldHeadsUp(entry));
     }
 
     @Test
-    public void testShouldPeek_noSuppressedPeek() {
+    public void testShouldHeadsUp_noSuppressedHeadsUp() throws Exception {
         when(mPowerManager.isScreenOn()).thenReturn(true);
         when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
         when(mNotificationData.shouldFilterOut(any())).thenReturn(false);
-        when(mSystemServicesProxy.isDreaming()).thenReturn(false);
+        when(mDreamManager.isDreaming()).thenReturn(false);
         when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);
 
         when(mNotificationData.shouldSuppressPeek(any())).thenReturn(false);
@@ -432,31 +432,31 @@
                 UserHandle.of(0), null, 0);
         NotificationData.Entry entry = new NotificationData.Entry(sbn);
 
-        assertTrue(mEntryManager.shouldPeek(entry, sbn));
+        assertTrue(mEntryManager.shouldHeadsUp(entry));
     }
 
     @Test
-    public void testPeek_disabledStatusBar() {
+    public void testHeadsUp_disabledStatusBar() {
         Notification n = new Notification.Builder(getContext(), "a").build();
         StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
                 UserHandle.of(0), null, 0);
         NotificationData.Entry entry = new NotificationData.Entry(sbn);
         mStatusBar.disable(StatusBarManager.DISABLE_EXPAND, 0, false /* animate */);
 
-        assertFalse("The panel shouldn't allow peek while disabled",
-                mStatusBar.shouldPeek(entry, sbn));
+        assertFalse("The panel shouldn't allow heads up while disabled",
+                mStatusBar.canHeadsUp(entry, sbn));
     }
 
     @Test
-    public void testPeek_disabledNotificationShade() {
+    public void testHeadsUp_disabledNotificationShade() {
         Notification n = new Notification.Builder(getContext(), "a").build();
         StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
                 UserHandle.of(0), null, 0);
         NotificationData.Entry entry = new NotificationData.Entry(sbn);
         mStatusBar.disable(0, StatusBarManager.DISABLE2_NOTIFICATION_SHADE, false /* animate */);
 
-        assertFalse("The panel shouldn't allow peek while notitifcation shade disabled",
-                mStatusBar.shouldPeek(entry, sbn));
+        assertFalse("The panel shouldn't allow heads up while notification shade disabled",
+                mStatusBar.canHeadsUp(entry, sbn));
     }
 
     @Test
@@ -472,7 +472,7 @@
     }
 
     @Test
-    public void testPanelOpenForPeek() {
+    public void testPanelOpenForHeadsUp() {
         when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
         when(mNotificationData.getActiveNotifications()).thenReturn(mNotificationList);
         when(mNotificationList.size()).thenReturn(5);
@@ -690,10 +690,10 @@
 
     public static class TestableNotificationEntryManager extends NotificationEntryManager {
 
-        public TestableNotificationEntryManager(SystemServicesProxy systemServicesProxy,
+        public TestableNotificationEntryManager(IDreamManager dreamManager,
                 PowerManager powerManager, Context context) {
             super(context);
-            mSystemServicesProxy = systemServicesProxy;
+            mDreamManager = dreamManager;
             mPowerManager = powerManager;
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java
index f8223f6..f7a7e04 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java
@@ -19,6 +19,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -83,4 +84,16 @@
                 & WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
         assertThat(flag).isEqualTo(0);
     }
+
+    @Test
+    public void testOnThemeChanged_doesntCrash() {
+        mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
+                mActivityManager, mDozeParameters);
+        mStatusBarWindowController.onThemeChanged();
+    }
+
+    @Test
+    public void testAdd_updatesVisibilityFlags() {
+        verify(mStatusBarView).setSystemUiVisibility(anyInt());
+    }
 }
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 41b3feb..90c10fd 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -4026,6 +4026,8 @@
     // - AUTOFILL_DATASET_AUTHENTICATED
     // - AUTOFILL_INVALID_AUTHENTICATION
     // - AUTOFILL_INVALID_DATASET_AUTHENTICATION
+    // NOTE: starting on OS Q, it also added the following fields:
+    // Tag FIELD_AUTOFILL_TEXT_LEN: length of the error message provided by the service
     AUTOFILL_REQUEST = 907;
 
     // Tag of a field for a package of an autofill service
@@ -4102,6 +4104,8 @@
     // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
     // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
     // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS Q, it also added the following fields:
+    // Tag FIELD_AUTOFILL_TEXT_LEN: length of the error message provided by the service
     AUTOFILL_DATA_SAVE_REQUEST = 918;
 
     // An auto-fill session was finished
@@ -6517,6 +6521,34 @@
     // OS: Q
     MOBILE_NETWORK = 1571;
 
+    // Tag of a field for the length of a text
+    FIELD_AUTOFILL_TEXT_LEN = 1572;
+
+    // Action: the notification assistant is changing a notification
+    // OS: Q
+    NOTIFICATION_ASSISTANT_ADJUSTMENT = 1573;
+
+    // Subtype: The people attached to a notification was changed
+    ADJUSTMENT_KEY_PEOPLE = 1574;
+
+    // Subtype: The snooze options attached to a notification was changed
+    ADJUSTMENT_KEY_SNOOZE_CRITERIA = 1575;
+
+    // Subtype: The group of a notification was changed
+    ADJUSTMENT_KEY_GROUP_KEY = 1576;
+
+    // Subtype: The user sentiment of a notification was changed
+    ADJUSTMENT_KEY_USER_SENTIMENT = 1577;
+
+    // Subtype: New actions have been added to a notification
+    ADJUSTMENT_KEY_SMART_ACTIONS = 1578;
+
+    // Subtype: New smart replies have been added to a notification
+    ADJUSTMENT_KEY_SMART_REPLIES = 1579;
+
+    // Subtype: The importance of a notification has been changed
+    ADJUSTMENT_KEY_IMPORTANCE = 1580;
+
     // ---- End Q Constants, all Q constants go above this line ----
 
     // Add new aosp constants above this line.
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index 371f932..cf9f233 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -170,6 +170,20 @@
      *                action.
      */
     public TouchExplorer(Context context, AccessibilityManagerService service) {
+        this(context, service, null);
+    }
+
+    /**
+     * Creates a new instance.
+     *
+     * @param context A context handle for accessing resources.
+     * @param service The service to notify touch interaction and gesture completed and to perform
+     *                action.
+     * @param detector The gesture detector to handle accessibility touch event. If null the default
+     *                one created in place, or for testing purpose.
+     */
+    public TouchExplorer(Context context, AccessibilityManagerService service,
+            AccessibilityGestureDetector detector) {
         mContext = context;
         mAms = service;
         mReceivedPointerTracker = new ReceivedPointerTracker();
@@ -186,7 +200,11 @@
         mSendTouchInteractionEndDelayed = new SendAccessibilityEventDelayed(
                 AccessibilityEvent.TYPE_TOUCH_INTERACTION_END,
                 mDetermineUserIntentTimeout);
-        mGestureDetector = new AccessibilityGestureDetector(context, this);
+        if (detector == null) {
+            mGestureDetector = new AccessibilityGestureDetector(context, this);
+        } else {
+            mGestureDetector = detector;
+        }
         final float density = context.getResources().getDisplayMetrics().density;
         mScaledMinPointerDistanceToUseMiddleLocation =
             (int) (MIN_POINTER_DISTANCE_TO_USE_MIDDLE_LOCATION_DIP * density);
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index b71d7a7..da52d40 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -1834,7 +1834,7 @@
 
                 if (provider.widgets.isEmpty()) {
                     // cancel the future updates
-                    cancelBroadcasts(provider);
+                    cancelBroadcastsLocked(provider);
 
                     // send the broacast saying that the provider is not in use any more
                     sendDisabledIntentLocked(provider);
@@ -1843,18 +1843,16 @@
         }
     }
 
-    private void cancelBroadcasts(Provider provider) {
+    private void cancelBroadcastsLocked(Provider provider) {
         if (DEBUG) {
-            Slog.i(TAG, "cancelBroadcasts() for " + provider);
+            Slog.i(TAG, "cancelBroadcastsLocked() for " + provider);
         }
         if (provider.broadcast != null) {
-            mAlarmManager.cancel(provider.broadcast);
-            long token = Binder.clearCallingIdentity();
-            try {
-                provider.broadcast.cancel();
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
+            final PendingIntent broadcast = provider.broadcast;
+            mSaveStateHandler.post(() -> {
+                    mAlarmManager.cancel(broadcast);
+                    broadcast.cancel();
+            });
             provider.broadcast = null;
         }
     }
@@ -2315,7 +2313,7 @@
         mProviders.remove(provider);
 
         // no need to send the DISABLE broadcast, since the receiver is gone anyway
-        cancelBroadcasts(provider);
+        cancelBroadcastsLocked(provider);
     }
 
     private void sendEnableIntentLocked(Provider p) {
@@ -2369,17 +2367,14 @@
                 Binder.restoreCallingIdentity(token);
             }
             if (!alreadyRegistered) {
-                long period = provider.info.updatePeriodMillis;
-                if (period < MIN_UPDATE_PERIOD) {
-                    period = MIN_UPDATE_PERIOD;
-                }
-                final long oldId = Binder.clearCallingIdentity();
-                try {
+                // Set the alarm outside of our locks; we've latched the first-time
+                // invariant and established the PendingIntent safely.
+                final long period = Math.max(provider.info.updatePeriodMillis, MIN_UPDATE_PERIOD);
+                final PendingIntent broadcast = provider.broadcast;
+                mSaveStateHandler.post(() ->
                     mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
-                            SystemClock.elapsedRealtime() + period, period, provider.broadcast);
-                } finally {
-                    Binder.restoreCallingIdentity(oldId);
-                }
+                            SystemClock.elapsedRealtime() + period, period, broadcast)
+                );
             }
         }
     }
@@ -3382,7 +3377,7 @@
                             // Reschedule for the new updatePeriodMillis (don't worry about handling
                             // it specially if updatePeriodMillis didn't change because we just sent
                             // an update, and the next one will be updatePeriodMillis from now).
-                            cancelBroadcasts(provider);
+                            cancelBroadcastsLocked(provider);
                             registerForBroadcastsLocked(provider, appWidgetIds);
                             // If it's currently showing, call back with the new
                             // AppWidgetProviderInfo.
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 8c8352f..78facf8 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -235,6 +235,13 @@
         }
     }
 
+    int getTargedSdkLocked() {
+        if (mInfo == null) {
+            return 0;
+        }
+        return mInfo.getServiceInfo().applicationInfo.targetSdkVersion;
+    }
+
     private boolean isSetupCompletedLocked() {
         final String setupComplete = Settings.Secure.getStringForUser(
                 mContext.getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, mUserId);
@@ -953,6 +960,7 @@
             pw.println();
             mInfo.dump(prefix2, pw);
             pw.print(prefix); pw.print("Service Label: "); pw.println(getServiceLabel());
+            pw.print(prefix); pw.print("Target SDK: "); pw.println(getTargedSdkLocked());
         }
         pw.print(prefix); pw.print("Component from settings: ");
             pw.println(getComponentNameFromSettings());
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index ad80cc26..d1b09ca 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -29,6 +29,7 @@
 import android.content.Intent;
 import android.content.IntentSender;
 import android.content.ServiceConnection;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.IBinder.DeathRecipient;
@@ -587,6 +588,7 @@
             }
             final RemoteFillService remoteService = getService();
             if (remoteService != null) {
+                if (sVerbose) Slog.v(LOG_TAG, "calling onFillRequest() for id=" + mRequest.getId());
                 try {
                     remoteService.mAutoFillService.onFillRequest(mRequest, mCallback);
                 } catch (RemoteException e) {
@@ -659,6 +661,7 @@
         public void run() {
             final RemoteFillService remoteService = getService();
             if (remoteService != null) {
+                if (sVerbose) Slog.v(LOG_TAG, "calling onSaveRequest()");
                 try {
                     remoteService.mAutoFillService.onSaveRequest(mRequest, mCallback);
                 } catch (RemoteException e) {
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index c9eb2d2..cf323fb 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -50,6 +50,7 @@
 import android.graphics.Rect;
 import android.metrics.LogMaker;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -63,6 +64,7 @@
 import android.service.autofill.Dataset;
 import android.service.autofill.FieldClassification;
 import android.service.autofill.FieldClassification.Match;
+import android.text.TextUtils;
 import android.service.autofill.FillContext;
 import android.service.autofill.FillRequest;
 import android.service.autofill.FillResponse;
@@ -744,12 +746,17 @@
 
     private void onFillRequestFailureOrTimeout(int requestId, boolean timedOut,
             @Nullable CharSequence message) {
+        boolean showMessage = !TextUtils.isEmpty(message);
         synchronized (mLock) {
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#onFillRequestFailureOrTimeout(req=" + requestId
                         + ") rejected - session: " + id + " destroyed");
                 return;
             }
+            if (sDebug) {
+                Slog.d(TAG, "finishing session due to service "
+                        + (timedOut ? "timeout" : "failure"));
+            }
             mService.resetLastResponse();
             final LogMaker requestLog = mRequestLogs.get(requestId);
             if (requestLog == null) {
@@ -757,8 +764,21 @@
             } else {
                 requestLog.setType(timedOut ? MetricsEvent.TYPE_CLOSE : MetricsEvent.TYPE_FAILURE);
             }
+            if (showMessage) {
+                final int targetSdk = mService.getTargedSdkLocked();
+                if (targetSdk >= Build.VERSION_CODES.Q) {
+                    showMessage = false;
+                    Slog.w(TAG, "onFillRequestFailureOrTimeout(): not showing '" + message
+                            + "' because service's targetting API " + targetSdk);
+                }
+                if (message != null) {
+                    requestLog.addTaggedData(MetricsEvent.FIELD_AUTOFILL_TEXT_LEN,
+                            message.length());
+                }
+            }
         }
-        if (message != null) {
+        notifyUnavailableToClient(AutofillManager.STATE_UNKNOWN_FAILED);
+        if (showMessage) {
             getUiForShowing().showError(message, this);
         }
         removeSelf();
@@ -793,6 +813,7 @@
     @Override
     public void onSaveRequestFailure(@Nullable CharSequence message,
             @NonNull String servicePackageName) {
+        boolean showMessage = !TextUtils.isEmpty(message);
         synchronized (mLock) {
             mIsSaving = false;
 
@@ -801,12 +822,26 @@
                         + id + " destroyed");
                 return;
             }
+            if (showMessage) {
+                final int targetSdk = mService.getTargedSdkLocked();
+                if (targetSdk >= Build.VERSION_CODES.Q) {
+                    showMessage = false;
+                    Slog.w(TAG, "onSaveRequestFailure(): not showing '" + message
+                            + "' because service's targetting API " + targetSdk);
+                }
+            }
         }
-        LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST, servicePackageName)
+        final LogMaker log =
+                newLogMaker(MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST, servicePackageName)
                 .setType(MetricsEvent.TYPE_FAILURE);
+        if (message != null) {
+            log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_TEXT_LEN, message.length());
+        }
         mMetricsLogger.write(log);
 
-        getUiForShowing().showError(message, this);
+        if (showMessage) {
+            getUiForShowing().showError(message, this);
+        }
         removeSelf();
     }
 
@@ -1206,7 +1241,7 @@
             // - not autofilled but matches a dataset value -> manuallyFilledIds
             if ((state & ViewState.STATE_CHANGED) != 0) {
                 // Check if autofilled value was changed
-                if ((state & ViewState.STATE_AUTOFILLED) != 0) {
+                if ((state & ViewState.STATE_AUTOFILLED_ONCE) != 0) {
                     final String datasetId = viewState.getDatasetId();
                     if (datasetId == null) {
                         // Sanity check - should never happen.
@@ -2181,12 +2216,28 @@
                     // Must check if this update was caused by autofilling the view, in which
                     // case we just update the value, but not the UI.
                     final AutofillValue filledValue = viewState.getAutofilledValue();
-                    if (filledValue != null && filledValue.equals(value)) {
-                        if (sVerbose) {
-                            Slog.v(TAG, "ignoring autofilled change on id " + id);
+                    if (filledValue != null) {
+                        if (filledValue.equals(value)) {
+                            if (sVerbose) {
+                                Slog.v(TAG, "ignoring autofilled change on id " + id);
+                            }
+                            viewState.resetState(ViewState.STATE_CHANGED);
+                            return;
                         }
-                        return;
+                        else {
+                            if ((viewState.id.equals(this.mCurrentViewId)) &&
+                                    (viewState.getState() & ViewState.STATE_AUTOFILLED) != 0) {
+                                // Remove autofilled state once field is changed after autofilling.
+                                if (sVerbose) {
+                                    Slog.v(TAG, "field changed after autofill on id " + id);
+                                }
+                                viewState.resetState(ViewState.STATE_AUTOFILLED);
+                                final ViewState currentView = mViewStates.get(mCurrentViewId);
+                                currentView.maybeCallOnFillReady(flags);
+                            }
+                        }
                     }
+
                     // Update the internal state...
                     viewState.setState(ViewState.STATE_CHANGED);
 
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index e6cd7e0..a8dae03 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -69,8 +69,10 @@
     public static final int STATE_RESTARTED_SESSION = 0x100;
     /** View is the URL bar of a package on compat mode. */
     public  static final int STATE_URL_BAR = 0x200;
-    /** View was asked to autofil but failed to do so. */
+    /** View was asked to autofill but failed to do so. */
     public static final int STATE_AUTOFILL_FAILED = 0x400;
+    /** View has been autofilled at least once. */
+    public static final int STATE_AUTOFILLED_ONCE = 0x800;
 
     public final AutofillId id;
 
@@ -161,6 +163,9 @@
         } else {
             mState |= state;
         }
+        if (state == STATE_AUTOFILLED) {
+            mState |= STATE_AUTOFILLED_ONCE;
+        }
     }
 
     void resetState(int state) {
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index 5962406..fe86ab3 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -43,6 +43,8 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.server.LocalServices;
+import com.android.server.UiModeManagerInternal;
 import com.android.server.UiThread;
 import com.android.server.autofill.Helper;
 
@@ -69,6 +71,7 @@
     private final MetricsLogger mMetricsLogger = new MetricsLogger();
 
     private final @NonNull OverlayControl mOverlayControl;
+    private final @NonNull UiModeManagerInternal mUiModeMgr;
 
     public interface AutoFillUiCallback {
         void authenticate(int requestId, int datasetIndex, @NonNull IntentSender intent,
@@ -86,6 +89,7 @@
     public AutoFillUI(@NonNull Context context) {
         mContext = context;
         mOverlayControl = new OverlayControl(context);
+        mUiModeMgr = LocalServices.getService(UiModeManagerInternal.class);
     }
 
     public void setCallback(@NonNull AutoFillUiCallback callback) {
@@ -193,7 +197,9 @@
             }
             hideAllUiThread(callback);
             mFillUi = new FillUi(mContext, response, focusedId,
-                    filterText, mOverlayControl, serviceLabel, serviceIcon, new FillUi.Callback() {
+                    filterText, mOverlayControl, serviceLabel, serviceIcon,
+                    mUiModeMgr.isNightMode(),
+                    new FillUi.Callback() {
                 @Override
                 public void onResponsePicked(FillResponse response) {
                     log.setType(MetricsEvent.TYPE_DETAIL);
@@ -332,7 +338,7 @@
                     }
                     mMetricsLogger.write(log);
                 }
-            }, isUpdate, compatMode);
+            }, mUiModeMgr.isNightMode(), isUpdate, compatMode);
         });
     }
 
@@ -368,6 +374,7 @@
         pw.println("Autofill UI");
         final String prefix = "  ";
         final String prefix2 = "    ";
+        pw.print(prefix); pw.print("Night mode: "); pw.println(mUiModeMgr.isNightMode());
         if (mFillUi != null) {
             pw.print(prefix); pw.println("showsFillUi: true");
             mFillUi.dump(pw, prefix2);
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index 68a495f..742d494 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -73,7 +73,10 @@
 final class FillUi {
     private static final String TAG = "FillUi";
 
-    private static final int THEME_ID = com.android.internal.R.style.Theme_DeviceDefault_Autofill;
+    private static final int THEME_ID_LIGHT =
+            com.android.internal.R.style.Theme_DeviceDefault_Light_Autofill;
+    private static final int THEME_ID_DARK =
+            com.android.internal.R.style.Theme_DeviceDefault_Autofill;
 
     private static final TypedValue sTempTypedValue = new TypedValue();
 
@@ -117,6 +120,8 @@
 
     private boolean mDestroyed;
 
+    private final int mThemeId;
+
     public static boolean isFullScreen(Context context) {
         if (sFullScreenMode != null) {
             if (sVerbose) Slog.v(TAG, "forcing full-screen mode to " + sFullScreenMode);
@@ -128,10 +133,13 @@
     FillUi(@NonNull Context context, @NonNull FillResponse response,
            @NonNull AutofillId focusedViewId, @NonNull @Nullable String filterText,
            @NonNull OverlayControl overlayControl, @NonNull CharSequence serviceLabel,
-           @NonNull Drawable serviceIcon, @NonNull Callback callback) {
+           @NonNull Drawable serviceIcon, boolean nightMode, @NonNull Callback callback) {
+        if (sVerbose) Slog.v(TAG, "nightMode: " + nightMode);
+        mThemeId = nightMode ? THEME_ID_DARK : THEME_ID_LIGHT;
         mCallback = callback;
         mFullScreen = isFullScreen(context);
-        mContext = new ContextThemeWrapper(context, THEME_ID);
+        mContext = new ContextThemeWrapper(context, mThemeId);
+
         final LayoutInflater inflater = LayoutInflater.from(mContext);
 
         final RemoteViews headerPresentation = response.getHeader();
@@ -216,7 +224,7 @@
             ViewGroup container = decor.findViewById(R.id.autofill_dataset_picker);
             final View content;
             try {
-                response.getPresentation().setApplyTheme(THEME_ID);
+                response.getPresentation().setApplyTheme(mThemeId);
                 content = response.getPresentation().apply(mContext, decor, interceptionHandler);
                 container.addView(content);
             } catch (RuntimeException e) {
@@ -257,7 +265,7 @@
             RemoteViews.OnClickHandler clickBlocker = null;
             if (headerPresentation != null) {
                 clickBlocker = newClickBlocker();
-                headerPresentation.setApplyTheme(THEME_ID);
+                headerPresentation.setApplyTheme(mThemeId);
                 mHeader = headerPresentation.apply(mContext, null, clickBlocker);
                 final LinearLayout headerContainer =
                         decor.findViewById(R.id.autofill_dataset_header);
@@ -275,7 +283,7 @@
                     if (clickBlocker == null) { // already set for header
                         clickBlocker = newClickBlocker();
                     }
-                    footerPresentation.setApplyTheme(THEME_ID);
+                    footerPresentation.setApplyTheme(mThemeId);
                     mFooter = footerPresentation.apply(mContext, null, clickBlocker);
                     // Footer not supported on some platform e.g. TV
                     if (sVerbose) Slog.v(TAG, "adding footer");
@@ -302,7 +310,7 @@
                     final View view;
                     try {
                         if (sVerbose) Slog.v(TAG, "setting remote view for " + focusedViewId);
-                        presentation.setApplyTheme(THEME_ID);
+                        presentation.setApplyTheme(mThemeId);
                         view = presentation.apply(mContext, null, interceptionHandler);
                     } catch (RuntimeException e) {
                         Slog.e(TAG, "Error inflating remote views", e);
@@ -732,6 +740,18 @@
         pw.print(prefix); pw.print("mContentWidth: "); pw.println(mContentWidth);
         pw.print(prefix); pw.print("mContentHeight: "); pw.println(mContentHeight);
         pw.print(prefix); pw.print("mDestroyed: "); pw.println(mDestroyed);
+        pw.print(prefix); pw.print("theme id: "); pw.print(mThemeId);
+        switch (mThemeId) {
+            case THEME_ID_DARK:
+                pw.println(" (dark)");
+                break;
+            case THEME_ID_LIGHT:
+                pw.println(" (light)");
+                break;
+            default:
+                pw.println("(UNKNOWN_MODE)");
+                break;
+        }
         if (mWindow != null) {
             pw.print(prefix); pw.print("mWindow: ");
             final String prefix2 = prefix + "  ";
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index 9d3d3cb..89b442e 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -72,9 +72,11 @@
  */
 final class SaveUi {
 
-    private static final String TAG = "AutofillSaveUi";
+    private static final String TAG = "SaveUi";
 
-    private static final int THEME_ID =
+    private static final int THEME_ID_LIGHT =
+            com.android.internal.R.style.Theme_DeviceDefault_Light_Autofill_Save;
+    private static final int THEME_ID_DARK =
             com.android.internal.R.style.Theme_DeviceDefault_Autofill_Save;
 
     public interface OnSaveListener {
@@ -144,6 +146,7 @@
     private final String mServicePackageName;
     private final ComponentName mComponentName;
     private final boolean mCompatMode;
+    private final int mThemeId;
 
     private boolean mDestroyed;
 
@@ -152,7 +155,9 @@
            @Nullable String servicePackageName, @NonNull ComponentName componentName,
            @NonNull SaveInfo info, @NonNull ValueFinder valueFinder,
            @NonNull OverlayControl overlayControl, @NonNull OnSaveListener listener,
-           boolean isUpdate, boolean compatMode) {
+           boolean nightMode, boolean isUpdate, boolean compatMode) {
+        if (sVerbose) Slog.v(TAG, "nightMode: " + nightMode);
+        mThemeId = nightMode ? THEME_ID_DARK : THEME_ID_LIGHT;
         mPendingUi= pendingUi;
         mListener = new OneActionThenDestroyListener(listener);
         mOverlayControl = overlayControl;
@@ -160,7 +165,7 @@
         mComponentName = componentName;
         mCompatMode = compatMode;
 
-        context = new ContextThemeWrapper(context, THEME_ID);
+        context = new ContextThemeWrapper(context, mThemeId);
         final LayoutInflater inflater = LayoutInflater.from(context);
         final View view = inflater.inflate(R.layout.autofill_save, null);
 
@@ -250,7 +255,7 @@
         }
         yesButton.setOnClickListener((v) -> mListener.onSave());
 
-        mDialog = new Dialog(context, THEME_ID);
+        mDialog = new Dialog(context, mThemeId);
         mDialog.setContentView(view);
 
         // Dialog can be dismissed when touched outside, but the negative listener should not be
@@ -337,7 +342,7 @@
 
         try {
             // Create the remote view peer.
-            template.setApplyTheme(THEME_ID);
+            template.setApplyTheme(mThemeId);
             final View customSubtitleView = template.apply(context, null, handler);
 
             // Apply batch updates (if any).
@@ -556,7 +561,18 @@
         pw.print(prefix); pw.print("service: "); pw.println(mServicePackageName);
         pw.print(prefix); pw.print("app: "); pw.println(mComponentName.toShortString());
         pw.print(prefix); pw.print("compat mode: "); pw.println(mCompatMode);
-
+        pw.print(prefix); pw.print("theme id: "); pw.print(mThemeId);
+        switch (mThemeId) {
+            case THEME_ID_DARK:
+                pw.println(" (dark)");
+                break;
+            case THEME_ID_LIGHT:
+                pw.println(" (light)");
+                break;
+            default:
+                pw.println("(UNKNOWN_MODE)");
+                break;
+        }
         final View view = mDialog.getWindow().getDecorView();
         final int[] loc = view.getLocationOnScreen();
         pw.print(prefix); pw.print("coordinates: ");
diff --git a/services/backup/java/com/android/server/backup/encryption/chunk/Chunk.java b/services/backup/java/com/android/server/backup/encryption/chunk/Chunk.java
new file mode 100644
index 0000000..5bec1a9
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/encryption/chunk/Chunk.java
@@ -0,0 +1,54 @@
+package com.android.server.backup.encryption.chunk;
+
+import android.util.proto.ProtoInputStream;
+
+import java.io.IOException;
+
+/**
+ * Information about a chunk entry in a protobuf. Only used for reading from a {@link
+ * ProtoInputStream}.
+ */
+public class Chunk {
+    /**
+     * Reads a Chunk from a {@link ProtoInputStream}. Expects the message to be of format {@link
+     * ChunksMetadataProto.Chunk}.
+     *
+     * @param inputStream currently at a {@link ChunksMetadataProto.Chunk} message.
+     * @throws IOException when the message is not structured as expected or a field can not be
+     *     read.
+     */
+    static Chunk readFromProto(ProtoInputStream inputStream) throws IOException {
+        Chunk result = new Chunk();
+
+        while (inputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (inputStream.getFieldNumber()) {
+                case (int) ChunksMetadataProto.Chunk.HASH:
+                    result.mHash = inputStream.readBytes(ChunksMetadataProto.Chunk.HASH);
+                    break;
+                case (int) ChunksMetadataProto.Chunk.LENGTH:
+                    result.mLength = inputStream.readInt(ChunksMetadataProto.Chunk.LENGTH);
+                    break;
+            }
+        }
+
+        return result;
+    }
+
+    private int mLength;
+    private byte[] mHash;
+
+    /** Private constructor. This class should only be instantiated by calling readFromProto. */
+    private Chunk() {
+        // Set default values for fields in case they are not available in the proto.
+        mHash = new byte[]{};
+        mLength = 0;
+    }
+
+    public int getLength() {
+        return mLength;
+    }
+
+    public byte[] getHash() {
+        return mHash;
+    }
+}
\ No newline at end of file
diff --git a/services/backup/java/com/android/server/backup/encryption/chunk/ChunkListing.java b/services/backup/java/com/android/server/backup/encryption/chunk/ChunkListing.java
new file mode 100644
index 0000000..2d2e88a
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/encryption/chunk/ChunkListing.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup.encryption.chunk;
+
+import android.annotation.Nullable;
+import android.util.proto.ProtoInputStream;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Chunk listing in a format optimized for quick look-up of chunks via their hash keys. This is
+ * useful when building an incremental backup. After a chunk has been produced, the algorithm can
+ * quickly look up whether the chunk existed in the previous backup by checking this chunk listing.
+ * It can then tell the server to use that chunk, through telling it the position and length of the
+ * chunk in the previous backup's blob.
+ */
+public class ChunkListing {
+    /**
+     * Reads a ChunkListing from a {@link ProtoInputStream}. Expects the message to be of format
+     * {@link ChunksMetadataProto.ChunkListing}.
+     *
+     * @param inputStream Currently at a {@link ChunksMetadataProto.ChunkListing} message.
+     * @throws IOException when the message is not structured as expected or a field can not be
+     *     read.
+     */
+    public static ChunkListing readFromProto(ProtoInputStream inputStream) throws IOException {
+        Map<ChunkHash, Entry> entries = new HashMap();
+
+        long start = 0;
+
+        while (inputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            if (inputStream.getFieldNumber() == (int) ChunksMetadataProto.ChunkListing.CHUNKS) {
+                long chunkToken = inputStream.start(ChunksMetadataProto.ChunkListing.CHUNKS);
+                Chunk chunk = Chunk.readFromProto(inputStream);
+                entries.put(new ChunkHash(chunk.getHash()), new Entry(start, chunk.getLength()));
+                start += chunk.getLength();
+                inputStream.end(chunkToken);
+            }
+        }
+
+        return new ChunkListing(entries);
+    }
+
+    private final Map<ChunkHash, Entry> mChunksByHash;
+
+    private ChunkListing(Map<ChunkHash, Entry> chunksByHash) {
+        mChunksByHash = Collections.unmodifiableMap(new HashMap<>(chunksByHash));
+    }
+
+    /** Returns {@code true} if there is a chunk with the given SHA-256 MAC key in the listing. */
+    public boolean hasChunk(ChunkHash hash) {
+        return mChunksByHash.containsKey(hash);
+    }
+
+    /**
+     * Returns the entry for the chunk with the given hash.
+     *
+     * @param hash The SHA-256 MAC of the plaintext of the chunk.
+     * @return The entry, containing position and length of the chunk in the backup blob, or null if
+     *     it does not exist.
+     */
+    @Nullable
+    public Entry getChunkEntry(ChunkHash hash) {
+        return mChunksByHash.get(hash);
+    }
+
+    /** Returns the number of chunks in this listing. */
+    public int getChunkCount() {
+        return mChunksByHash.size();
+    }
+
+    /** Information about a chunk entry in a backup blob - i.e., its position and length. */
+    public static final class Entry {
+        private final int mLength;
+        private final long mStart;
+
+        private Entry(long start, int length) {
+            mStart = start;
+            mLength = length;
+        }
+
+        /** Returns the length of the chunk in bytes. */
+        public int getLength() {
+            return mLength;
+        }
+
+        /** Returns the start position of the chunk in the backup blob, in bytes. */
+        public long getStart() {
+            return mStart;
+        }
+    }
+}
diff --git a/services/backup/java/com/android/server/backup/encryption/chunk/EncryptedChunkOrdering.java b/services/backup/java/com/android/server/backup/encryption/chunk/EncryptedChunkOrdering.java
new file mode 100644
index 0000000..3a6d1f6
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/encryption/chunk/EncryptedChunkOrdering.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup.encryption.chunk;
+
+import java.util.Arrays;
+
+/**
+ * Holds the bytes of an encrypted {@link ChunksMetadataProto.ChunkOrdering}.
+ *
+ * <p>TODO(b/116575321): After all code is ported, remove the factory method and rename
+ * encryptedChunkOrdering() to getBytes().
+ */
+public class EncryptedChunkOrdering {
+    /**
+     * Constructs a new object holding the given bytes of an encrypted {@link
+     * ChunksMetadataProto.ChunkOrdering}.
+     *
+     * <p>Note that this just holds an ordering which is already encrypted, it does not encrypt the
+     * ordering.
+     */
+    public static EncryptedChunkOrdering create(byte[] encryptedChunkOrdering) {
+        return new EncryptedChunkOrdering(encryptedChunkOrdering);
+    }
+
+    private final byte[] mEncryptedChunkOrdering;
+
+    public byte[] encryptedChunkOrdering() {
+        return mEncryptedChunkOrdering;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof EncryptedChunkOrdering)) {
+            return false;
+        }
+
+        EncryptedChunkOrdering encryptedChunkOrdering = (EncryptedChunkOrdering) o;
+        return Arrays.equals(
+                mEncryptedChunkOrdering, encryptedChunkOrdering.mEncryptedChunkOrdering);
+    }
+
+    @Override
+    public int hashCode() {
+        return Arrays.hashCode(mEncryptedChunkOrdering);
+    }
+
+    private EncryptedChunkOrdering(byte[] encryptedChunkOrdering) {
+        mEncryptedChunkOrdering = encryptedChunkOrdering;
+    }
+}
diff --git a/services/backup/java/com/android/server/backup/keyvalue/AgentException.java b/services/backup/java/com/android/server/backup/keyvalue/AgentException.java
new file mode 100644
index 0000000..e2ca351
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/keyvalue/AgentException.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup.keyvalue;
+
+/**
+ * This represents something wrong with a specific package. For example:
+ * <ul>
+ *     <li>Package unknown.
+ *     <li>Package is not eligible for backup anymore.
+ *     <li>Backup agent timed out.
+ *     <li>Backup agent wrote protected keys.
+ *     <li>...
+ * </ul>
+ *
+ * @see KeyValueBackupTask
+ * @see TaskException
+ */
+class AgentException extends BackupException {
+    static AgentException transitory() {
+        return new AgentException(/* transitory */ true);
+    }
+
+    static AgentException transitory(Exception cause) {
+        return new AgentException(/* transitory */ true, cause);
+    }
+
+    static AgentException permanent() {
+        return new AgentException(/* transitory */ false);
+    }
+
+    static AgentException permanent(Exception cause) {
+        return new AgentException(/* transitory */ false, cause);
+    }
+
+    private final boolean mTransitory;
+
+    private AgentException(boolean transitory) {
+        mTransitory = transitory;
+    }
+
+    private AgentException(boolean transitory, Exception cause) {
+        super(cause);
+        mTransitory = transitory;
+    }
+
+    boolean isTransitory() {
+        return mTransitory;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/events/StartedDragingEvent.java b/services/backup/java/com/android/server/backup/keyvalue/BackupException.java
similarity index 60%
copy from packages/SystemUI/src/com/android/systemui/stackdivider/events/StartedDragingEvent.java
copy to services/backup/java/com/android/server/backup/keyvalue/BackupException.java
index 5d19851..27b2d35 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/events/StartedDragingEvent.java
+++ b/services/backup/java/com/android/server/backup/keyvalue/BackupException.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2018 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,12 +14,20 @@
  * limitations under the License
  */
 
-package com.android.systemui.stackdivider.events;
+package com.android.server.backup.keyvalue;
 
-import com.android.systemui.recents.events.EventBus;
+import android.util.AndroidException;
 
 /**
- * Sent when the divider is being draged either manually or by an animation.
+ * Key-value backup task exception.
+ *
+ * @see AgentException
+ * @see TaskException
  */
-public class StartedDragingEvent extends EventBus.Event {
+class BackupException extends AndroidException {
+    BackupException() {}
+
+    BackupException(Exception cause) {
+        super(cause);
+    }
 }
diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java
index 54e6b1d..bb8a1d1 100644
--- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java
+++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java
@@ -54,7 +54,7 @@
 public class KeyValueBackupReporter {
     @VisibleForTesting static final String TAG = "KeyValueBackupTask";
     private static final boolean DEBUG = BackupManagerService.DEBUG;
-    @VisibleForTesting static final boolean MORE_DEBUG = BackupManagerService.MORE_DEBUG || true;
+    @VisibleForTesting static final boolean MORE_DEBUG = BackupManagerService.MORE_DEBUG || false;
 
     static void onNewThread(String threadName) {
         if (DEBUG) {
@@ -153,16 +153,18 @@
                 mObserver, packageName, BackupManager.ERROR_BACKUP_NOT_ALLOWED);
     }
 
-    void onBindAgentError(SecurityException e) {
-        Slog.d(TAG, "Error in bind/backup", e);
-    }
-
     void onAgentUnknown(String packageName) {
         Slog.d(TAG, "Package does not exist, skipping");
         BackupObserverUtils.sendBackupOnPackageResult(
                 mObserver, packageName, BackupManager.ERROR_PACKAGE_NOT_FOUND);
     }
 
+    void onBindAgentError(String packageName, SecurityException e) {
+        Slog.d(TAG, "Error in bind/backup", e);
+        BackupObserverUtils.sendBackupOnPackageResult(
+                mObserver, packageName, BackupManager.ERROR_AGENT_FAILURE);
+    }
+
     void onAgentError(String packageName) {
         if (MORE_DEBUG) {
             Slog.i(TAG, "Agent failure for " + packageName + ", re-staging");
@@ -190,6 +192,8 @@
     void onCallAgentDoBackupError(String packageName, boolean callingAgent, Exception e) {
         if (callingAgent) {
             Slog.e(TAG, "Error invoking agent on " + packageName + ": " + e);
+            BackupObserverUtils.sendBackupOnPackageResult(
+                    mObserver, packageName, BackupManager.ERROR_AGENT_FAILURE);
         } else {
             Slog.e(TAG, "Error before invoking agent on " + packageName + ": " + e);
         }
@@ -220,12 +224,8 @@
         }
     }
 
-    void onReadAgentDataError(String packageName, IOException e) {
-        Slog.w(TAG, "Unable read backup data for " + packageName + ": " + e);
-    }
-
-    void onWriteWidgetDataError(String packageName, IOException e) {
-        Slog.w(TAG, "Unable to save widget data for " + packageName + ": " + e);
+    void onAgentDataError(String packageName, IOException e) {
+        Slog.w(TAG, "Unable to read/write agent data for " + packageName + ": " + e);
     }
 
     void onDigestError(NoSuchAlgorithmException e) {
@@ -243,16 +243,12 @@
         }
     }
 
-    void onSendDataToTransport(String packageName) {
+    void onTransportPerformBackup(String packageName) {
         if (MORE_DEBUG) {
             Slog.v(TAG, "Sending non-empty data to transport for " + packageName);
         }
     }
 
-    void onNonIncrementalAndNonIncrementalRequired() {
-        Slog.e(TAG, "Transport requested non-incremental but already the case");
-    }
-
     void onEmptyData(PackageInfo packageInfo) {
         if (MORE_DEBUG) {
             Slog.i(TAG, "No backup data written, not calling transport");
@@ -302,13 +298,20 @@
                 /* extras */ null);
     }
 
+    void onPackageBackupNonIncrementalAndNonIncrementalRequired(String packageName) {
+        Slog.e(TAG, "Transport requested non-incremental but already the case");
+        BackupObserverUtils.sendBackupOnPackageResult(
+                mObserver, packageName, BackupManager.ERROR_TRANSPORT_ABORTED);
+        EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, packageName);
+    }
+
     void onPackageBackupTransportFailure(String packageName) {
         BackupObserverUtils.sendBackupOnPackageResult(
                 mObserver, packageName, BackupManager.ERROR_TRANSPORT_ABORTED);
         EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, packageName);
     }
 
-    void onPackageBackupError(String packageName, Exception e) {
+    void onPackageBackupTransportError(String packageName, Exception e) {
         Slog.e(TAG, "Transport error backing up " + packageName, e);
         BackupObserverUtils.sendBackupOnPackageResult(
                 mObserver, packageName, BackupManager.ERROR_TRANSPORT_ABORTED);
diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
index e915ce1..6904b3f 100644
--- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
+++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
@@ -16,6 +16,7 @@
 
 package com.android.server.backup.keyvalue;
 
+import static android.app.ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL;
 import static android.os.ParcelFileDescriptor.MODE_CREATE;
 import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
 import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
@@ -25,8 +26,8 @@
 import static com.android.server.backup.BackupManagerService.OP_PENDING;
 import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP;
 
+import android.annotation.IntDef;
 import android.annotation.Nullable;
-import android.app.ApplicationThreadConstants;
 import android.app.IBackupAgent;
 import android.app.backup.BackupAgent;
 import android.app.backup.BackupDataInput;
@@ -47,7 +48,6 @@
 import android.os.SELinux;
 import android.os.UserHandle;
 import android.os.WorkSource;
-import android.util.Pair;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -77,6 +77,8 @@
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
@@ -173,10 +175,8 @@
     private static final AtomicInteger THREAD_COUNT = new AtomicInteger();
     private static final String BLANK_STATE_FILE_NAME = "blank_state";
     private static final String PM_PACKAGE = BackupManagerService.PACKAGE_MANAGER_SENTINEL;
-    @VisibleForTesting
-    public static final String STAGING_FILE_SUFFIX = ".data";
-    @VisibleForTesting
-    public static final String NEW_STATE_FILE_SUFFIX = ".new";
+    @VisibleForTesting public static final String STAGING_FILE_SUFFIX = ".data";
+    @VisibleForTesting public static final String NEW_STATE_FILE_SUFFIX = ".new";
 
     /**
      * Creates a new {@link KeyValueBackupTask} for key-value backup operation, spins up a new
@@ -244,13 +244,13 @@
     private final int mCurrentOpToken;
     private final File mStateDirectory;
     private final File mDataDirectory;
+    private final File mBlankStateFile;
     private final List<String> mOriginalQueue;
     private final List<String> mQueue;
     private final List<String> mPendingFullBackups;
     private final Object mQueueLock;
     @Nullable private final DataChangedJournal mJournal;
 
-    private int mStatus;
     @Nullable private PerformFullTransportBackupTask mFullBackupTask;
     @Nullable private IBackupAgent mAgent;
     @Nullable private PackageInfo mCurrentPackage;
@@ -316,6 +316,7 @@
         mDataDirectory = mBackupManagerService.getDataDir();
         mCurrentOpToken = backupManagerService.generateRandomIntegerToken();
         mQueueLock = mBackupManagerService.getQueueLock();
+        mBlankStateFile = new File(mStateDirectory, BLANK_STATE_FILE_NAME);
     }
 
     private void registerTask() {
@@ -331,45 +332,43 @@
     public void run() {
         Process.setThreadPriority(THREAD_PRIORITY);
 
-        boolean processQueue = startTask();
-        while (processQueue && !mQueue.isEmpty() && !mCancelled) {
-            String packageName = mQueue.remove(0);
-            if (PM_PACKAGE.equals(packageName)) {
-                processQueue = backupPm();
-            } else {
-                processQueue = backupPackage(packageName);
+        int status = BackupTransport.TRANSPORT_OK;
+        try {
+            startTask();
+            while (!mQueue.isEmpty() && !mCancelled) {
+                String packageName = mQueue.remove(0);
+                try {
+                    if (PM_PACKAGE.equals(packageName)) {
+                        backupPm();
+                    } else {
+                        backupPackage(packageName);
+                    }
+                } catch (AgentException e) {
+                    if (e.isTransitory()) {
+                        // We try again this package in the next backup pass.
+                        mBackupManagerService.dataChangedImpl(packageName);
+                    }
+                }
             }
+        } catch (TaskException e) {
+            if (e.isStateCompromised()) {
+                mBackupManagerService.resetBackupState(mStateDirectory);
+            }
+            revertTask();
+            status = e.getStatus();
         }
-        finishTask();
+        finishTask(status);
     }
 
-    /** Returns whether to consume next queue package. */
-    private boolean handleAgentResult(@Nullable PackageInfo packageInfo, RemoteResult result) {
-        if (result == RemoteResult.FAILED_THREAD_INTERRUPTED) {
-            // Not an explicit cancel, we need to flag it.
-            mCancelled = true;
-            mReporter.onAgentCancelled(packageInfo);
-            cleanUpAgentForAgentError();
-            return false;
+    /** Returns transport status. */
+    private int sendDataToTransport(@Nullable PackageInfo packageInfo)
+            throws AgentException, TaskException {
+        try {
+            return sendDataToTransport();
+        } catch (IOException e) {
+            mReporter.onAgentDataError(packageInfo.packageName, e);
+            throw TaskException.causedBy(e);
         }
-        if (result == RemoteResult.FAILED_CANCELLED) {
-            mReporter.onAgentCancelled(packageInfo);
-            cleanUpAgentForAgentError();
-            return false;
-        }
-        if (result == RemoteResult.FAILED_TIMED_OUT) {
-            mReporter.onAgentTimedOut(packageInfo);
-            cleanUpAgentForAgentError();
-            return true;
-        }
-        Preconditions.checkState(result.isPresent());
-        long agentResult = result.get();
-        if (agentResult == BackupAgent.RESULT_ERROR) {
-            mReporter.onAgentResultError(packageInfo);
-            cleanUpAgentForAgentError();
-            return true;
-        }
-        return sendDataToTransport();
     }
 
     @Override
@@ -378,11 +377,10 @@
     @Override
     public void operationComplete(long unusedResult) {}
 
-    /** Returns whether to consume next queue package. */
-    private boolean startTask() {
+    private void startTask() throws TaskException {
         if (mBackupManagerService.isBackupOperationInProgress()) {
             mReporter.onSkipBackup();
-            return false;
+            throw TaskException.create();
         }
 
         // Unfortunately full backup task constructor registers the task with BMS, so we have to
@@ -390,11 +388,9 @@
         mFullBackupTask = createFullBackupTask(mPendingFullBackups);
         registerTask();
 
-        mStatus = BackupTransport.TRANSPORT_OK;
-
         if (mQueue.isEmpty() && mPendingFullBackups.isEmpty()) {
             mReporter.onEmptyQueueAtStart();
-            return false;
+            return;
         }
         // We only backup PM if it was explicitly in the queue or if it's incremental.
         boolean backupPm = mQueue.remove(PM_PACKAGE) || !mNonIncremental;
@@ -415,20 +411,18 @@
             if (pmState.length() <= 0) {
                 mReporter.onInitializeTransport(transportName);
                 mBackupManagerService.resetBackupState(mStateDirectory);
-                mStatus = transport.initializeDevice();
-                mReporter.onTransportInitialized(mStatus);
+                int status = transport.initializeDevice();
+                mReporter.onTransportInitialized(status);
+                if (status != BackupTransport.TRANSPORT_OK) {
+                    throw TaskException.stateCompromised();
+                }
             }
+        } catch (TaskException e) {
+            throw e;
         } catch (Exception e) {
             mReporter.onInitializeTransportError(e);
-            mStatus = BackupTransport.TRANSPORT_ERROR;
+            throw TaskException.stateCompromised();
         }
-
-        if (mStatus != BackupTransport.TRANSPORT_OK) {
-            mBackupManagerService.resetBackupState(mStateDirectory);
-            return false;
-        }
-
-        return true;
     }
 
     private PerformFullTransportBackupTask createFullBackupTask(List<String> packages) {
@@ -446,120 +440,82 @@
                 mUserInitiated);
     }
 
-    /** Returns whether to consume next queue package. */
-    private boolean backupPm() {
-        RemoteResult agentResult = null;
+    private void backupPm() throws TaskException {
+        mReporter.onStartPackageBackup(PM_PACKAGE);
+        mCurrentPackage = new PackageInfo();
+        mCurrentPackage.packageName = PM_PACKAGE;
+
         try {
-            mCurrentPackage = new PackageInfo();
-            mCurrentPackage.packageName = PM_PACKAGE;
-
-            // Since PM is running in the system process we can set up its agent directly.
-            BackupAgent pmAgent = mBackupManagerService.makeMetadataAgent();
-            mAgent = IBackupAgent.Stub.asInterface(pmAgent.onBind());
-
-            Pair<Integer, RemoteResult> statusAndResult = extractAgentData(PM_PACKAGE, mAgent);
-            mStatus = statusAndResult.first;
-            agentResult = statusAndResult.second;
-        } catch (Exception e) {
+            extractPmAgentData(mCurrentPackage);
+            int status = sendDataToTransport(mCurrentPackage);
+            cleanUpAgentForTransportStatus(status);
+        } catch (AgentException | TaskException e) {
             mReporter.onExtractPmAgentDataError(e);
-            mStatus = BackupTransport.TRANSPORT_ERROR;
+            cleanUpAgentForError(e);
+            // PM agent failure is task failure.
+            throw TaskException.stateCompromised(e);
         }
-
-        if (mStatus != BackupTransport.TRANSPORT_OK) {
-            // In this case either extractAgentData() already made the agent clean-up or we haven't
-            // prepared the state for calling the agent, in either case we don't need to clean-up.
-            mBackupManagerService.resetBackupState(mStateDirectory);
-            return false;
-        }
-
-        Preconditions.checkNotNull(agentResult);
-        return handleAgentResult(mCurrentPackage, agentResult);
     }
 
-    /** Returns whether to consume next queue package. */
-    private boolean backupPackage(String packageName) {
+    private void backupPackage(String packageName) throws AgentException, TaskException {
         mReporter.onStartPackageBackup(packageName);
-        mStatus = BackupTransport.TRANSPORT_OK;
+        mCurrentPackage = getPackageForBackup(packageName);
 
-        // Verify that the requested app is eligible for key-value backup.
-        RemoteResult agentResult = null;
         try {
-            mCurrentPackage = mPackageManager.getPackageInfo(
-                    packageName, PackageManager.GET_SIGNING_CERTIFICATES);
-            ApplicationInfo applicationInfo = mCurrentPackage.applicationInfo;
-            if (!AppBackupUtils.appIsEligibleForBackup(applicationInfo, mPackageManager)) {
-                // The manifest has changed. This won't happen again because the app won't be
-                // requesting further backups.
-                mReporter.onPackageNotEligibleForBackup(packageName);
-                return true;
-            }
-
-            if (AppBackupUtils.appGetsFullBackup(mCurrentPackage)) {
-                // Initially enqueued for key-value backup, but only supports full-backup now.
-                mReporter.onPackageEligibleForFullBackup(packageName);
-                return true;
-            }
-
-            if (AppBackupUtils.appIsStopped(applicationInfo)) {
-                // Just as it won't receive broadcasts, we won't run it for backup.
-                mReporter.onPackageStopped(packageName);
-                return true;
-            }
-
-            try {
-                mBackupManagerService.setWorkSource(new WorkSource(applicationInfo.uid));
-                IBackupAgent agent =
-                        mBackupManagerService.bindToAgentSynchronous(
-                                applicationInfo,
-                                ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL);
-                if (agent != null) {
-                    mAgent = agent;
-                    Pair<Integer, RemoteResult> statusAndResult =
-                            extractAgentData(packageName, agent);
-                    mStatus = statusAndResult.first;
-                    agentResult = statusAndResult.second;
-                } else {
-                    // Timeout waiting for the agent to bind.
-                    mStatus = BackupTransport.AGENT_ERROR;
-                }
-            } catch (SecurityException e) {
-                mReporter.onBindAgentError(e);
-                mStatus = BackupTransport.AGENT_ERROR;
-            }
-        } catch (PackageManager.NameNotFoundException e) {
-            mStatus = BackupTransport.AGENT_UNKNOWN;
-        } finally {
-            mBackupManagerService.setWorkSource(null);
+            extractAgentData(mCurrentPackage);
+            int status = sendDataToTransport(mCurrentPackage);
+            cleanUpAgentForTransportStatus(status);
+        } catch (AgentException | TaskException e) {
+            cleanUpAgentForError(e);
+            throw e;
         }
-
-        if (mStatus != BackupTransport.TRANSPORT_OK) {
-            // In this case either extractAgentData() already made the agent clean-up or we haven't
-            // prepared the state for calling the agent, in either case we don't need to clean-up.
-            Preconditions.checkState(mAgent == null);
-
-            if (mStatus == BackupTransport.AGENT_ERROR) {
-                mReporter.onAgentError(packageName);
-                mBackupManagerService.dataChangedImpl(packageName);
-                mStatus = BackupTransport.TRANSPORT_OK;
-                return true;
-            }
-
-            if (mStatus == BackupTransport.AGENT_UNKNOWN) {
-                mReporter.onAgentUnknown(packageName);
-                mStatus = BackupTransport.TRANSPORT_OK;
-                return true;
-            }
-
-            // Transport-level failure, re-enqueue everything.
-            revertTask();
-            return false;
-        }
-
-        Preconditions.checkNotNull(agentResult);
-        return handleAgentResult(mCurrentPackage, agentResult);
     }
 
-    private void finishTask() {
+    private PackageInfo getPackageForBackup(String packageName) throws AgentException {
+        final PackageInfo packageInfo;
+        try {
+            packageInfo =
+                    mPackageManager.getPackageInfo(
+                            packageName, PackageManager.GET_SIGNING_CERTIFICATES);
+        } catch (PackageManager.NameNotFoundException e) {
+            mReporter.onAgentUnknown(packageName);
+            throw AgentException.permanent(e);
+        }
+        ApplicationInfo applicationInfo = packageInfo.applicationInfo;
+        if (!AppBackupUtils.appIsEligibleForBackup(applicationInfo, mPackageManager)) {
+            mReporter.onPackageNotEligibleForBackup(packageName);
+            throw AgentException.permanent();
+        }
+        if (AppBackupUtils.appGetsFullBackup(packageInfo)) {
+            mReporter.onPackageEligibleForFullBackup(packageName);
+            throw AgentException.permanent();
+        }
+        if (AppBackupUtils.appIsStopped(applicationInfo)) {
+            mReporter.onPackageStopped(packageName);
+            throw AgentException.permanent();
+        }
+        return packageInfo;
+    }
+
+    private IBackupAgent bindAgent(PackageInfo packageInfo) throws AgentException {
+        String packageName = packageInfo.packageName;
+        final IBackupAgent agent;
+        try {
+            agent =
+                    mBackupManagerService.bindToAgentSynchronous(
+                            packageInfo.applicationInfo, BACKUP_MODE_INCREMENTAL);
+            if (agent == null) {
+                mReporter.onAgentError(packageName);
+                throw AgentException.transitory();
+            }
+        } catch (SecurityException e) {
+            mReporter.onBindAgentError(packageName, e);
+            throw AgentException.transitory(e);
+        }
+        return agent;
+    }
+
+    private void finishTask(int status) {
         // Mark packages that we couldn't backup as pending backup.
         for (String packageName : mQueue) {
             mBackupManagerService.dataChangedImpl(packageName);
@@ -576,7 +532,7 @@
         // If we succeeded and this is the first time we've done a backup, we can record the current
         // backup dataset token.
         long currentToken = mBackupManagerService.getCurrentToken();
-        if ((mStatus == BackupTransport.TRANSPORT_OK) && (currentToken == 0)) {
+        if ((status == BackupTransport.TRANSPORT_OK) && (currentToken == 0)) {
             try {
                 IBackupTransport transport = mTransportClient.connectOrThrow(callerLogString);
                 mBackupManagerService.setCurrentToken(transport.getCurrentRestoreSet());
@@ -589,9 +545,14 @@
 
         synchronized (mQueueLock) {
             mBackupManagerService.setBackupRunning(false);
-            if (mStatus == BackupTransport.TRANSPORT_NOT_INITIALIZED) {
+            if (status == BackupTransport.TRANSPORT_NOT_INITIALIZED) {
                 mReporter.onTransportNotInitialized();
-                triggerTransportInitializationLocked();
+                try {
+                    triggerTransportInitializationLocked();
+                } catch (Exception e) {
+                    mReporter.onPendingInitializeTransportError(e);
+                    status = BackupTransport.TRANSPORT_ERROR;
+                }
             }
         }
 
@@ -605,7 +566,7 @@
         }
 
         if (!mCancelled
-                && mStatus == BackupTransport.TRANSPORT_OK
+                && status == BackupTransport.TRANSPORT_OK
                 && mFullBackupTask != null
                 && !mPendingFullBackups.isEmpty()) {
             mReporter.onStartFullBackup(mPendingFullBackups);
@@ -621,7 +582,7 @@
             mFullBackupTask.unregisterTask();
         }
         mTaskFinishedListener.onFinished(callerLogString);
-        mReporter.onBackupFinished(getBackupFinishedStatus(mCancelled, mStatus));
+        mReporter.onBackupFinished(getBackupFinishedStatus(mCancelled, status));
         mBackupManagerService.getWakelock().release();
     }
 
@@ -642,17 +603,12 @@
     }
 
     @GuardedBy("mQueueLock")
-    private void triggerTransportInitializationLocked() {
-        try {
-            IBackupTransport transport =
-                    mTransportClient.connectOrThrow("KVBT.triggerTransportInitializationLocked");
-            mBackupManagerService.getPendingInits().add(transport.name());
-            deletePmStateFile();
-            mBackupManagerService.backupNow();
-        } catch (Exception e) {
-            mReporter.onPendingInitializeTransportError(e);
-            mStatus = BackupTransport.TRANSPORT_ERROR;
-        }
+    private void triggerTransportInitializationLocked() throws Exception {
+        IBackupTransport transport =
+                mTransportClient.connectOrThrow("KVBT.triggerTransportInitializationLocked");
+        mBackupManagerService.getPendingInits().add(transport.name());
+        deletePmStateFile();
+        mBackupManagerService.backupNow();
     }
 
     /** Removes PM state, triggering initialization in the next key-value task. */
@@ -660,35 +616,69 @@
         new File(mStateDirectory, PM_PACKAGE).delete();
     }
 
+    /** Same as {@link #extractAgentData(PackageInfo)}, but only for PM package. */
+    private void extractPmAgentData(PackageInfo packageInfo) throws AgentException, TaskException {
+        Preconditions.checkArgument(packageInfo.packageName.equals(PM_PACKAGE));
+        BackupAgent pmAgent = mBackupManagerService.makeMetadataAgent();
+        mAgent = IBackupAgent.Stub.asInterface(pmAgent.onBind());
+        extractAgentData(packageInfo, mAgent);
+    }
+
     /**
-     * Returns a {@link Pair}. The first of the pair contains the status. In case the status is
-     * {@link BackupTransport#TRANSPORT_OK}, the second of the pair contains the agent result,
-     * otherwise {@code null}.
+     * Binds to the agent and extracts its backup data. If this method returns, the data in {@code
+     * mBackupData} is ready to be sent to the transport, otherwise it will throw.
+     *
+     * <p>This method leaves agent resources (agent binder, files and file-descriptors) opened that
+     * need to be cleaned up after terminating, either successfully or exceptionally. This clean-up
+     * can be done with methods {@link #cleanUpAgentForTransportStatus(int)} and {@link
+     * #cleanUpAgentForError(BackupException)}, depending on whether data was successfully sent to
+     * the transport or not. It's the caller responsibility to do the clean-up or delegate it.
      */
-    private Pair<Integer, RemoteResult> extractAgentData(String packageName, IBackupAgent agent) {
+    private void extractAgentData(PackageInfo packageInfo) throws AgentException, TaskException {
+        mBackupManagerService.setWorkSource(new WorkSource(packageInfo.applicationInfo.uid));
+        try {
+            mAgent = bindAgent(packageInfo);
+            extractAgentData(packageInfo, mAgent);
+        } finally {
+            mBackupManagerService.setWorkSource(null);
+        }
+    }
+
+    /**
+     * Calls agent {@link IBackupAgent#doBackup(ParcelFileDescriptor, ParcelFileDescriptor,
+     * ParcelFileDescriptor, long, IBackupCallback, int)} and waits for the result. If this method
+     * returns, the data in {@code mBackupData} is ready to be sent to the transport, otherwise it
+     * will throw.
+     *
+     * <p>This method creates files and file-descriptors for the agent that need to be deleted and
+     * closed after terminating, either successfully or exceptionally. This clean-up can be done
+     * with methods {@link #cleanUpAgentForTransportStatus(int)} and {@link
+     * #cleanUpAgentForError(BackupException)}, depending on whether data was successfully sent to
+     * the transport or not. It's the caller responsibility to do the clean-up or delegate it.
+     */
+    private void extractAgentData(PackageInfo packageInfo, IBackupAgent agent)
+            throws AgentException, TaskException {
+        String packageName = packageInfo.packageName;
         mReporter.onExtractAgentData(packageName);
 
-        File blankStateFile = new File(mStateDirectory, BLANK_STATE_FILE_NAME);
         mSavedStateFile = new File(mStateDirectory, packageName);
         mBackupDataFile = new File(mDataDirectory, packageName + STAGING_FILE_SUFFIX);
         mNewStateFile = new File(mStateDirectory, packageName + NEW_STATE_FILE_SUFFIX);
         mReporter.onAgentFilesReady(mBackupDataFile);
 
-        mSavedState = null;
-        mBackupData = null;
-        mNewState = null;
-
         boolean callingAgent = false;
         final RemoteResult agentResult;
         try {
-            File savedStateFileForAgent = (mNonIncremental) ? blankStateFile : mSavedStateFile;
+            File savedStateFileForAgent = (mNonIncremental) ? mBlankStateFile : mSavedStateFile;
             // MODE_CREATE to make an empty file if necessary
-            mSavedState = ParcelFileDescriptor.open(
-                    savedStateFileForAgent, MODE_READ_ONLY | MODE_CREATE);
-            mBackupData = ParcelFileDescriptor.open(
-                    mBackupDataFile, MODE_READ_WRITE | MODE_CREATE | MODE_TRUNCATE);
-            mNewState = ParcelFileDescriptor.open(
-                    mNewStateFile, MODE_READ_WRITE | MODE_CREATE | MODE_TRUNCATE);
+            mSavedState =
+                    ParcelFileDescriptor.open(savedStateFileForAgent, MODE_READ_ONLY | MODE_CREATE);
+            mBackupData =
+                    ParcelFileDescriptor.open(
+                            mBackupDataFile, MODE_READ_WRITE | MODE_CREATE | MODE_TRUNCATE);
+            mNewState =
+                    ParcelFileDescriptor.open(
+                            mNewStateFile, MODE_READ_WRITE | MODE_CREATE | MODE_TRUNCATE);
 
             if (!SELinux.restorecon(mBackupDataFile)) {
                 mReporter.onRestoreconFailed(mBackupDataFile);
@@ -713,15 +703,40 @@
                             "doBackup()");
         } catch (Exception e) {
             mReporter.onCallAgentDoBackupError(packageName, callingAgent, e);
-            cleanUpAgentForAgentError();
-            // TODO: Remove the check on callingAgent when RemoteCall supports local agent calls.
-            int status =
-                    callingAgent ? BackupTransport.AGENT_ERROR : BackupTransport.TRANSPORT_ERROR;
-            return Pair.create(status, null);
+            if (callingAgent) {
+                throw AgentException.transitory(e);
+            } else {
+                throw TaskException.create();
+            }
+        } finally {
+            mBlankStateFile.delete();
         }
-        blankStateFile.delete();
+        checkAgentResult(packageInfo, agentResult);
+    }
 
-        return Pair.create(BackupTransport.TRANSPORT_OK, agentResult);
+    private void checkAgentResult(PackageInfo packageInfo, RemoteResult result)
+            throws AgentException, TaskException {
+        if (result == RemoteResult.FAILED_THREAD_INTERRUPTED) {
+            // Not an explicit cancel, we need to flag it.
+            mCancelled = true;
+            mReporter.onAgentCancelled(packageInfo);
+            throw TaskException.create();
+        }
+        if (result == RemoteResult.FAILED_CANCELLED) {
+            mReporter.onAgentCancelled(packageInfo);
+            throw TaskException.create();
+        }
+        if (result == RemoteResult.FAILED_TIMED_OUT) {
+            mReporter.onAgentTimedOut(packageInfo);
+            throw AgentException.transitory();
+        }
+        Preconditions.checkState(result.isPresent());
+        long resultCode = result.get();
+        if (resultCode == BackupAgent.RESULT_ERROR) {
+            mReporter.onAgentResultError(packageInfo);
+            throw AgentException.transitory();
+        }
+        Preconditions.checkState(resultCode == BackupAgent.RESULT_SUCCESS);
     }
 
     private void agentFail(IBackupAgent agent, String message) {
@@ -801,94 +816,79 @@
         }
     }
 
-    /** Returns whether to consume next queue package. */
-    private boolean sendDataToTransport() {
+    /** Returns transport status. */
+    private int sendDataToTransport() throws AgentException, TaskException, IOException {
         Preconditions.checkState(mBackupData != null);
+        checkBackupData(mCurrentPackage.applicationInfo, mBackupDataFile);
 
         String packageName = mCurrentPackage.packageName;
-        ApplicationInfo applicationInfo = mCurrentPackage.applicationInfo;
-
-        boolean writingWidgetData = false;
-        try {
-            if (!validateBackupData(applicationInfo, mBackupDataFile)) {
-                cleanUpAgentForAgentError();
-                return true;
-            }
-            writingWidgetData = true;
-            writeWidgetPayloadIfAppropriate(mBackupData.getFileDescriptor(), packageName);
-        } catch (IOException e) {
-            if (writingWidgetData) {
-                mReporter.onWriteWidgetDataError(packageName, e);
-            } else {
-                mReporter.onReadAgentDataError(packageName, e);
-            }
-            cleanUpAgentForAgentError();
-            revertTask();
-            return false;
-        }
+        writeWidgetPayloadIfAppropriate(mBackupData.getFileDescriptor(), packageName);
 
         boolean nonIncremental = mSavedStateFile.length() == 0;
-        long size = mBackupDataFile.length();
-        if (size > 0) {
-            try (ParcelFileDescriptor backupData =
-                         ParcelFileDescriptor.open(mBackupDataFile, MODE_READ_ONLY)) {
-                IBackupTransport transport =
-                        mTransportClient.connectOrThrow("KVBT.sendDataToTransport()");
-                mReporter.onSendDataToTransport(packageName);
-                int flags = getPerformBackupFlags(mUserInitiated, nonIncremental);
-
-                mStatus = transport.performBackup(mCurrentPackage, backupData, flags);
-                if (mStatus == BackupTransport.TRANSPORT_OK) {
-                    mStatus = transport.finishBackup();
-                }
-            } catch (Exception e) {
-                mReporter.onPackageBackupError(packageName, e);
-                mStatus = BackupTransport.TRANSPORT_ERROR;
-            }
-        } else {
-            mReporter.onEmptyData(mCurrentPackage);
-            mStatus = BackupTransport.TRANSPORT_OK;
-        }
-
-        if (nonIncremental
-                && mStatus == BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED) {
-            mReporter.onNonIncrementalAndNonIncrementalRequired();
-            mStatus = BackupTransport.TRANSPORT_ERROR;
-        }
-
-
-        boolean processQueue = handleTransportStatus(mStatus, packageName, size);
-        // We might report quota exceeded to the agent in handleTransportStatus() above, so we
-        // only clean-up after it.
-        cleanUpAgentForTransportStatus(mStatus);
-        return processQueue;
+        int status = transportPerformBackup(mCurrentPackage, mBackupDataFile, nonIncremental);
+        handleTransportStatus(status, packageName, mBackupDataFile.length());
+        return status;
     }
 
-    /** Returns whether to consume next queue package. */
-    private boolean handleTransportStatus(int status, String packageName, long size) {
+    private int transportPerformBackup(
+            PackageInfo packageInfo, File backupDataFile, boolean nonIncremental)
+            throws TaskException {
+        String packageName = packageInfo.packageName;
+        long size = backupDataFile.length();
+        if (size <= 0) {
+            mReporter.onEmptyData(packageInfo);
+            return BackupTransport.TRANSPORT_OK;
+        }
+
+        int status;
+        try (ParcelFileDescriptor backupData =
+                ParcelFileDescriptor.open(backupDataFile, MODE_READ_ONLY)) {
+            IBackupTransport transport =
+                    mTransportClient.connectOrThrow("KVBT.transportPerformBackup()");
+            mReporter.onTransportPerformBackup(packageName);
+            int flags = getPerformBackupFlags(mUserInitiated, nonIncremental);
+
+            status = transport.performBackup(packageInfo, backupData, flags);
+            if (status == BackupTransport.TRANSPORT_OK) {
+                status = transport.finishBackup();
+            }
+        } catch (Exception e) {
+            mReporter.onPackageBackupTransportError(packageName, e);
+            throw TaskException.causedBy(e);
+        }
+
+        if (nonIncremental && status == BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED) {
+            mReporter.onPackageBackupNonIncrementalAndNonIncrementalRequired(packageName);
+            throw TaskException.create();
+        }
+
+        return status;
+    }
+
+    private void handleTransportStatus(int status, String packageName, long size)
+            throws TaskException, AgentException {
         if (status == BackupTransport.TRANSPORT_OK) {
             mReporter.onPackageBackupComplete(packageName, size);
-            return true;
-        }
-        if (status == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
-            mReporter.onPackageBackupRejected(packageName);
-            return true;
+            return;
         }
         if (status == BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED) {
             mReporter.onPackageBackupNonIncrementalRequired(mCurrentPackage);
             // Immediately retry the current package.
             mQueue.add(0, packageName);
-            return true;
+            return;
+        }
+        if (status == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
+            mReporter.onPackageBackupRejected(packageName);
+            throw AgentException.permanent();
         }
         if (status == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
             mReporter.onPackageBackupQuotaExceeded(packageName);
             agentDoQuotaExceeded(mAgent, packageName, size);
-            return true;
+            throw AgentException.permanent();
         }
         // Any other error here indicates a transport-level failure.
         mReporter.onPackageBackupTransportFailure(packageName);
-        revertTask();
-        return false;
+        throw TaskException.forStatus(status);
     }
 
     private void agentDoQuotaExceeded(@Nullable IBackupAgent agent, String packageName, long size) {
@@ -908,19 +908,17 @@
     }
 
     /**
-     * For system apps and pseudo-apps always return {@code true}. For regular apps returns whether
-     * {@code backupDataFile} doesn't have any protected keys.
-     *
-     * <p>If the app has attempted to write any protected keys we also crash them.
+     * For system apps and pseudo-apps never throws. For regular apps throws {@link AgentException}
+     * if {@code backupDataFile} has any protected keys, also crashing the app.
      */
-    private boolean validateBackupData(
-            @Nullable ApplicationInfo applicationInfo, File backupDataFile) throws IOException {
+    private void checkBackupData(@Nullable ApplicationInfo applicationInfo, File backupDataFile)
+            throws IOException, AgentException {
         if (applicationInfo == null || (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
             // System apps and pseudo-apps can write what they want.
-            return true;
+            return;
         }
         try (ParcelFileDescriptor backupData =
-                     ParcelFileDescriptor.open(backupDataFile, MODE_READ_ONLY)) {
+                ParcelFileDescriptor.open(backupDataFile, MODE_READ_ONLY)) {
             BackupDataInput backupDataInput = new BackupDataInput(backupData.getFileDescriptor());
             while (backupDataInput.readNextHeader()) {
                 String key = backupDataInput.getKey();
@@ -928,12 +926,11 @@
                     mReporter.onAgentIllegalKey(mCurrentPackage, key);
                     // Crash them if they wrote any protected keys.
                     agentFail(mAgent, "Illegal backup key: " + key);
-                    return false;
+                    throw AgentException.permanent();
                 }
                 backupDataInput.skipEntityData();
             }
         }
-        return true;
     }
 
     private int getPerformBackupFlags(boolean userInitiated, boolean nonIncremental) {
@@ -1009,44 +1006,39 @@
         }
     }
 
-    /** Cleans-up after having called the agent. */
+    /**
+     * Cleans up agent resources opened by {@link #extractAgentData(PackageInfo)} for exceptional
+     * case.
+     *
+     * <p>Note: Declaring exception parameter so that the caller only calls this when an exception
+     * is thrown.
+     */
+    private void cleanUpAgentForError(BackupException exception) {
+        cleanUpAgent(StateTransaction.DISCARD_NEW);
+    }
+
+    /**
+     * Cleans up agent resources opened by {@link #extractAgentData(PackageInfo)} according to
+     * transport status returned in {@link #sendDataToTransport(PackageInfo)}.
+     */
     private void cleanUpAgentForTransportStatus(int status) {
-        updateFiles(status);
-        cleanUpAgent();
-    }
-
-    /** Cleans-up if we failed to call the agent. */
-    private void cleanUpAgentForAgentError() {
-        mBackupDataFile.delete();
-        mNewStateFile.delete();
-        cleanUpAgent();
-    }
-
-    private void updateFiles(int status) {
         switch (status) {
             case BackupTransport.TRANSPORT_OK:
-                mBackupDataFile.delete();
-                mNewStateFile.renameTo(mSavedStateFile);
+                cleanUpAgent(StateTransaction.COMMIT_NEW);
                 break;
             case BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED:
-                mSavedStateFile.delete();
-                mBackupDataFile.delete();
-                mNewStateFile.delete();
+                cleanUpAgent(StateTransaction.DISCARD_ALL);
                 break;
             default:
-                // Includes:
-                // * BackupTransport.TRANSPORT_PACKAGE_REJECTED
-                // * BackupTransport.TRANSPORT_QUOTA_EXCEEDED
-                // * BackupTransport.TRANSPORT_ERROR
-                mBackupDataFile.delete();
-                mNewStateFile.delete();
-                break;
+                // All other transport statuses are properly converted to agent or task exceptions.
+                throw new AssertionError();
         }
     }
 
-    /** Cleans-up file-descriptors and unbinds agent. */
-    private void cleanUpAgent() {
-        mAgent = null;
+    private void cleanUpAgent(@StateTransaction int stateTransaction) {
+        applyStateTransaction(stateTransaction);
+        mBackupDataFile.delete();
+        mBlankStateFile.delete();
         tryCloseFileDescriptor(mSavedState, "old state");
         tryCloseFileDescriptor(mBackupData, "backup data");
         tryCloseFileDescriptor(mNewState, "new state");
@@ -1058,6 +1050,24 @@
         if (mCurrentPackage.applicationInfo != null) {
             mBackupManagerService.unbindAgent(mCurrentPackage.applicationInfo);
         }
+        mAgent = null;
+    }
+
+    private void applyStateTransaction(@StateTransaction int stateTransaction) {
+        switch (stateTransaction) {
+            case StateTransaction.COMMIT_NEW:
+                mNewStateFile.renameTo(mSavedStateFile);
+                break;
+            case StateTransaction.DISCARD_NEW:
+                mNewStateFile.delete();
+                break;
+            case StateTransaction.DISCARD_ALL:
+                mSavedStateFile.delete();
+                mNewStateFile.delete();
+                break;
+            default:
+                throw new IllegalArgumentException("Unknown state transaction " + stateTransaction);
+        }
     }
 
     private void tryCloseFileDescriptor(@Nullable Closeable closeable, String logName) {
@@ -1079,4 +1089,16 @@
         mPendingCall = null;
         return result;
     }
+
+    @IntDef({
+        StateTransaction.COMMIT_NEW,
+        StateTransaction.DISCARD_NEW,
+        StateTransaction.DISCARD_ALL,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface StateTransaction {
+        int COMMIT_NEW = 0;
+        int DISCARD_NEW = 1;
+        int DISCARD_ALL = 2;
+    }
 }
diff --git a/services/backup/java/com/android/server/backup/keyvalue/TaskException.java b/services/backup/java/com/android/server/backup/keyvalue/TaskException.java
new file mode 100644
index 0000000..08d2895
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/keyvalue/TaskException.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup.keyvalue;
+
+import android.app.backup.BackupTransport;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * The key-value backup task has failed, no more packages will be processed and we shouldn't attempt
+ * any more backups now. These can be caused by transport failures (as opposed to agent failures).
+ *
+ * @see KeyValueBackupTask
+ * @see AgentException
+ */
+class TaskException extends BackupException {
+    private static final int DEFAULT_STATUS = BackupTransport.TRANSPORT_ERROR;
+
+    static TaskException stateCompromised() {
+        return new TaskException(/* stateCompromised */ true, DEFAULT_STATUS);
+    }
+
+    static TaskException stateCompromised(Exception cause) {
+        if (cause instanceof TaskException) {
+            TaskException exception = (TaskException) cause;
+            return new TaskException(cause, /* stateCompromised */ true, exception.getStatus());
+        }
+        return new TaskException(cause, /* stateCompromised */ true, DEFAULT_STATUS);
+    }
+
+    static TaskException forStatus(int status) {
+        Preconditions.checkArgument(
+                status != BackupTransport.TRANSPORT_OK, "Exception based on TRANSPORT_OK");
+        return new TaskException(/* stateCompromised */ false, status);
+    }
+
+    static TaskException causedBy(Exception cause) {
+        if (cause instanceof TaskException) {
+            return (TaskException) cause;
+        }
+        return new TaskException(cause, /* stateCompromised */ false, DEFAULT_STATUS);
+    }
+
+    static TaskException create() {
+        return new TaskException(/* stateCompromised */ false, DEFAULT_STATUS);
+    }
+
+    private final boolean mStateCompromised;
+    private final int mStatus;
+
+    private TaskException(Exception cause, boolean stateCompromised, int status) {
+        super(cause);
+        mStateCompromised = stateCompromised;
+        mStatus = status;
+    }
+
+    private TaskException(boolean stateCompromised, int status) {
+        mStateCompromised = stateCompromised;
+        mStatus = status;
+    }
+
+    boolean isStateCompromised() {
+        return mStateCompromised;
+    }
+
+    int getStatus() {
+        return mStatus;
+    }
+}
diff --git a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
index 9af952d..c933833 100644
--- a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
@@ -105,7 +105,7 @@
                 try {
                     IBackupTransport transport =
                             transportClient.connectOrThrow(
-                                    "AppBackupUtils.appIsEligibleForBackupAtRuntime");
+                                    "AppBackupUtils.appIsRunningAndEligibleForBackupWithTransport");
                     return transport.isAppEligibleForBackup(
                             packageInfo, AppBackupUtils.appGetsFullBackup(packageInfo));
                 } catch (Exception e) {
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 998e441..c2aec29 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -16,6 +16,15 @@
 
 package com.android.server;
 
+import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
+import static android.app.AppOpsManager.UID_STATE_CACHED;
+import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
+import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
+import static android.app.AppOpsManager.UID_STATE_LAST_NON_RESTRICTED;
+import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
+import static android.app.AppOpsManager.UID_STATE_TOP;
+import static android.app.AppOpsManager._NUM_UID_STATE;
+
 import android.Manifest;
 import android.app.ActivityManager;
 import android.app.ActivityThread;
@@ -98,15 +107,6 @@
 import java.util.List;
 import java.util.Map;
 
-import static android.app.AppOpsManager._NUM_UID_STATE;
-import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
-import static android.app.AppOpsManager.UID_STATE_CACHED;
-import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
-import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
-import static android.app.AppOpsManager.UID_STATE_LAST_NON_RESTRICTED;
-import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
-import static android.app.AppOpsManager.UID_STATE_TOP;
-
 public class AppOpsService extends IAppOpsService.Stub {
     static final String TAG = "AppOps";
     static final boolean DEBUG = false;
@@ -1016,7 +1016,7 @@
                     scheduleWriteLocked();
                 }
             } else {
-                if (uidState.opModes.get(code) == mode) {
+                if (uidState.opModes.indexOfKey(code) >= 0 && uidState.opModes.get(code) == mode) {
                     return;
                 }
                 if (mode == defaultMode) {
@@ -1971,6 +1971,7 @@
                             continue;
                         }
                         boolean doAllPackages = uidState.opModes != null
+                                && uidState.opModes.indexOfKey(code) >= 0
                                 && uidState.opModes.get(code) == AppOpsManager.MODE_FOREGROUND;
                         if (uidState.pkgOps != null) {
                             for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) {
diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java
index 15673a7..872261a 100644
--- a/services/core/java/com/android/server/BinderCallsStatsService.java
+++ b/services/core/java/com/android/server/BinderCallsStatsService.java
@@ -118,10 +118,22 @@
             this.mBinderCallsStats = binderCallsStats;
         }
 
+        /** @see BinderCallsStats#reset */
+        public void reset() {
+            mBinderCallsStats.reset();
+        }
+
+        /**
+         * @see BinderCallsStats#getExportedCallStats.
+         *
+         * Note that binder calls stats will be reset by statsd every time
+         * the data is exported.
+         */
         public ArrayList<BinderCallsStats.ExportedCallStat> getExportedCallStats() {
             return mBinderCallsStats.getExportedCallStats();
         }
 
+        /** @see BinderCallsStats#getExportedExceptionStats */
         public ArrayMap<String, Integer> getExportedExceptionStats() {
             return mBinderCallsStats.getExportedExceptionStats();
         }
@@ -190,6 +202,15 @@
                     reset();
                     pw.println("binder_calls_stats reset.");
                     return;
+                } else if ("--enable".equals(arg)) {
+                    Binder.setObserver(mBinderCallsStats);
+                    return;
+                } else if ("--disable".equals(arg)) {
+                    Binder.setObserver(null);
+                    return;
+                } else if ("--no-sampling".equals(arg)) {
+                    mBinderCallsStats.setSamplingInterval(1);
+                    return;
                 } else if ("--enable-detailed-tracking".equals(arg)) {
                     SystemProperties.set(PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING, "1");
                     mBinderCallsStats.setDetailedTracking(true);
@@ -203,6 +224,9 @@
                 } else if ("-h".equals(arg)) {
                     pw.println("binder_calls_stats commands:");
                     pw.println("  --reset: Reset stats");
+                    pw.println("  --enable: Enable tracking binder calls");
+                    pw.println("  --disable: Disables tracking binder calls");
+                    pw.println("  --no-sampling: Tracks all calls");
                     pw.println("  --enable-detailed-tracking: Enables detailed tracking");
                     pw.println("  --disable-detailed-tracking: Disables detailed tracking");
                     return;
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 7602090..e41a09e 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -35,6 +35,9 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
 import static android.net.NetworkCapabilities.TRANSPORT_VPN;
+import static android.os.Process.INVALID_UID;
+import static android.system.OsConstants.IPPROTO_TCP;
+import static android.system.OsConstants.IPPROTO_UDP;
 
 import static com.android.internal.util.Preconditions.checkNotNull;
 
@@ -49,6 +52,7 @@
 import android.content.IntentFilter;
 import android.content.res.Configuration;
 import android.database.ContentObserver;
+import android.net.ConnectionInfo;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.PacketKeepalive;
 import android.net.IConnectivityManager;
@@ -75,7 +79,6 @@
 import android.net.NetworkState;
 import android.net.NetworkUtils;
 import android.net.NetworkWatchlistManager;
-import android.net.Proxy;
 import android.net.ProxyInfo;
 import android.net.RouteInfo;
 import android.net.UidRange;
@@ -83,6 +86,7 @@
 import android.net.VpnService;
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.NetworkEvent;
+import android.net.netlink.InetDiagMessage;
 import android.net.util.MultinetworkPolicyTracker;
 import android.os.Binder;
 import android.os.Build;
@@ -153,7 +157,6 @@
 import com.android.server.connectivity.NetworkMonitor;
 import com.android.server.connectivity.NetworkNotificationManager;
 import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
-import com.android.server.connectivity.PacManager;
 import com.android.server.connectivity.PermissionMonitor;
 import com.android.server.connectivity.ProxyTracker;
 import com.android.server.connectivity.Tethering;
@@ -1680,6 +1683,11 @@
                 "ConnectivityService");
     }
 
+    private boolean checkNetworkStackPermission() {
+        return PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.NETWORK_STACK);
+    }
+
     private void enforceConnectivityRestrictedNetworksPermission() {
         try {
             mContext.enforceCallingOrSelfPermission(
@@ -5922,4 +5930,49 @@
             pw.println("    Get airplane mode.");
         }
     }
+
+    /**
+     * Caller either needs to be an active VPN, or hold the NETWORK_STACK permission
+     * for testing.
+     */
+    private Vpn enforceActiveVpnOrNetworkStackPermission() {
+        if (checkNetworkStackPermission()) {
+            return null;
+        }
+        final int uid = Binder.getCallingUid();
+        final int user = UserHandle.getUserId(uid);
+        synchronized (mVpns) {
+            Vpn vpn = mVpns.get(user);
+            try {
+                if (vpn.getVpnInfo().ownerUid == uid) return vpn;
+            } catch (NullPointerException e) {
+                /* vpn is null, or VPN is not connected and getVpnInfo() is null. */
+            }
+        }
+        throw new SecurityException("App must either be an active VPN or have the NETWORK_STACK "
+                + "permission");
+    }
+
+    /**
+     * @param connectionInfo the connection to resolve.
+     * @return {@code uid} if the connection is found and the app has permission to observe it
+     * (e.g., if it is associated with the calling VPN app's tunnel) or {@code INVALID_UID} if the
+     * connection is not found.
+     */
+    public int getConnectionOwnerUid(ConnectionInfo connectionInfo) {
+        final Vpn vpn = enforceActiveVpnOrNetworkStackPermission();
+        if (connectionInfo.protocol != IPPROTO_TCP && connectionInfo.protocol != IPPROTO_UDP) {
+            throw new IllegalArgumentException("Unsupported protocol " + connectionInfo.protocol);
+        }
+
+        final int uid = InetDiagMessage.getConnectionOwnerUid(connectionInfo.protocol,
+                connectionInfo.local, connectionInfo.remote);
+
+        /* Filter out Uids not associated with the VPN. */
+        if (vpn != null && !vpn.appliesToUid(uid)) {
+            return INVALID_UID;
+        }
+
+        return uid;
+    }
 }
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 380f6a7..a69d416 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -1490,23 +1490,19 @@
         }
     }
 
-    private static final String TUNNEL_OP = "STOPSHIP"; // = AppOpsManager.OP_MANAGE_IPSEC_TUNNELS;
+    private static final String TUNNEL_OP = AppOpsManager.OPSTR_MANAGE_IPSEC_TUNNELS;
 
     private void enforceTunnelPermissions(String callingPackage) {
         checkNotNull(callingPackage, "Null calling package cannot create IpSec tunnels");
-        if (false) { // STOPSHIP if this line is present
-            switch (getAppOpsManager().noteOp(
-                        TUNNEL_OP,
-                        Binder.getCallingUid(), callingPackage)) {
-                case AppOpsManager.MODE_DEFAULT:
-                    mContext.enforceCallingOrSelfPermission(
-                            android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "IpSecService");
-                    break;
-                case AppOpsManager.MODE_ALLOWED:
-                    return;
-                default:
-                    throw new SecurityException("Request to ignore AppOps for non-legacy API");
-            }
+        switch (getAppOpsManager().noteOp(TUNNEL_OP, Binder.getCallingUid(), callingPackage)) {
+            case AppOpsManager.MODE_DEFAULT:
+                mContext.enforceCallingOrSelfPermission(
+                        android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "IpSecService");
+                break;
+            case AppOpsManager.MODE_ALLOWED:
+                return;
+            default:
+                throw new SecurityException("Request to ignore AppOps for non-legacy API");
         }
     }
 
diff --git a/services/core/java/com/android/server/LooperStatsService.java b/services/core/java/com/android/server/LooperStatsService.java
index ab7bf28..4f0e170 100644
--- a/services/core/java/com/android/server/LooperStatsService.java
+++ b/services/core/java/com/android/server/LooperStatsService.java
@@ -93,10 +93,12 @@
         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
         List<LooperStats.ExportedEntry> entries = mStats.getEntries();
         entries.sort(Comparator
-                .comparing((LooperStats.ExportedEntry entry) -> entry.threadName)
+                .comparing((LooperStats.ExportedEntry entry) -> entry.workSourceUid)
+                .thenComparing(entry -> entry.threadName)
                 .thenComparing(entry -> entry.handlerClassName)
                 .thenComparing(entry -> entry.messageName));
         String header = String.join(",", Arrays.asList(
+                "work_source_uid",
                 "thread_name",
                 "handler_class",
                 "message_name",
@@ -110,11 +112,11 @@
                 "exception_count"));
         pw.println(header);
         for (LooperStats.ExportedEntry entry : entries) {
-            pw.printf("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n", entry.threadName,
-                    entry.handlerClassName, entry.messageName, entry.isInteractive,
-                    entry.messageCount, entry.recordedMessageCount, entry.totalLatencyMicros,
-                    entry.maxLatencyMicros, entry.cpuUsageMicros, entry.maxCpuUsageMicros,
-                    entry.exceptionCount);
+            pw.printf("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n", entry.workSourceUid,
+                    entry.threadName, entry.handlerClassName, entry.messageName,
+                    entry.isInteractive, entry.messageCount, entry.recordedMessageCount,
+                    entry.totalLatencyMicros, entry.maxLatencyMicros, entry.cpuUsageMicros,
+                    entry.maxCpuUsageMicros, entry.exceptionCount);
         }
     }
 
@@ -189,6 +191,10 @@
             } else if ("reset".equals(cmd)) {
                 mStats.reset();
                 return 0;
+            } else if ("sampling_interval".equals(cmd)) {
+                int sampling = Integer.parseUnsignedInt(getNextArgRequired());
+                setSamplingInterval(sampling);
+                return 0;
             } else {
                 return handleDefaultCommands(cmd);
             }
@@ -198,9 +204,10 @@
         public void onHelp() {
             final PrintWriter pw = getOutPrintWriter();
             pw.println(LOOPER_STATS_SERVICE_NAME + " commands:");
-            pw.println("  enable: Enable collecting stats");
-            pw.println("  disable: Disable collecting stats");
-            pw.println("  reset: Reset stats");
+            pw.println("  enable: Enable collecting stats.");
+            pw.println("  disable: Disable collecting stats.");
+            pw.println("  sampling_interval: Change the sampling interval.");
+            pw.println("  reset: Reset stats.");
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/events/StoppedDragingEvent.java b/services/core/java/com/android/server/UiModeManagerInternal.java
similarity index 63%
copy from packages/SystemUI/src/com/android/systemui/stackdivider/events/StoppedDragingEvent.java
copy to services/core/java/com/android/server/UiModeManagerInternal.java
index c50d6d6..ef29069 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/events/StoppedDragingEvent.java
+++ b/services/core/java/com/android/server/UiModeManagerInternal.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2018 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -11,15 +11,17 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
  */
 
-package com.android.systemui.stackdivider.events;
-
-import com.android.systemui.recents.events.EventBus;
+package com.android.server;
 
 /**
- * Sent when the divider isn't draging anymore.
+ * UiModeManager local system service interface.
+ *
+ * @hide Only for use within the system server.
  */
-public class StoppedDragingEvent extends EventBus.Event {
+public abstract class UiModeManagerInternal {
+
+    public abstract boolean isNightMode();
 }
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index cb03255..5538e72 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -42,31 +42,25 @@
 import android.os.ServiceManager;
 import android.os.ShellCallback;
 import android.os.ShellCommand;
-import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.dreams.Sandman;
 import android.service.vr.IVrManager;
 import android.service.vr.IVrStateCallbacks;
-import android.text.TextUtils;
 import android.util.Slog;
 
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Collections;
-
 import com.android.internal.R;
 import com.android.internal.app.DisableCarModeActivity;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.util.DumpUtils;
-import com.android.server.power.ShutdownThread;
 import com.android.server.twilight.TwilightListener;
 import com.android.server.twilight.TwilightManager;
 import com.android.server.twilight.TwilightState;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
 final class UiModeManagerService extends SystemService {
     private static final String TAG = UiModeManager.class.getSimpleName();
     private static final boolean LOG = false;
@@ -114,6 +108,8 @@
 
     private PowerManager.WakeLock mWakeLock;
 
+    private final LocalService mLocalService = new LocalService();
+
     public UiModeManagerService(Context context) {
         super(context);
     }
@@ -248,6 +244,7 @@
 
         }, TAG + ".onStart");
         publishBinderService(Context.UI_MODE_SERVICE, mService);
+        publishLocalService(UiModeManagerInternal.class, mLocalService);
     }
 
     private final IUiModeManager.Stub mService = new IUiModeManager.Stub() {
@@ -373,7 +370,8 @@
             pw.println("Current UI Mode Service state:");
             pw.print("  mDockState="); pw.print(mDockState);
                     pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState);
-            pw.print("  mNightMode="); pw.print(mNightMode);
+            pw.print("  mNightMode="); pw.print(mNightMode); pw.print(" (");
+                    pw.print(Shell.nightModeToStr(mNightMode)); pw.print(") ");
                     pw.print(" mNightModeLocked="); pw.print(mNightModeLocked);
                     pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled);
                     pw.print(" mComputedNightMode="); pw.print(mComputedNightMode);
@@ -466,7 +464,7 @@
             uiMode |= mNightMode << 4;
         }
 
-        if (mPowerSave && !mNightModeLocked) {
+        if (mPowerSave) {
             uiMode &= ~Configuration.UI_MODE_NIGHT_NO;
             uiMode |= Configuration.UI_MODE_NIGHT_YES;
         }
@@ -845,4 +843,22 @@
             }
         }
     }
+
+    public final class LocalService extends UiModeManagerInternal {
+
+        @Override
+        public boolean isNightMode() {
+            synchronized (mLock) {
+                final boolean isIt = (mConfiguration.uiMode & Configuration.UI_MODE_NIGHT_YES) != 0;
+                if (LOG) {
+                    Slog.d(TAG,
+                        "LocalService.isNightMode(): mNightMode=" + mNightMode
+                        + "; mComputedNightMode=" + mComputedNightMode
+                        + "; uiMode=" + mConfiguration.uiMode
+                        + "; isIt=" + isIt);
+                }
+                return isIt;
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index e5aa3f4..461d39d 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -629,7 +629,7 @@
                 return false;
             }
 
-            IIntentSender target = mAm.getIntentSenderLocked(
+            IIntentSender target = mAm.mPendingIntentController.getIntentSender(
                     ActivityManager.INTENT_SENDER_SERVICE, callingPackage,
                     callingUid, userId, null, null, 0, new Intent[]{service},
                     new String[]{service.resolveType(mAm.mContext.getContentResolver())},
@@ -2490,7 +2490,7 @@
                                  PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
             app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
             app.thread.scheduleCreateService(r, r.serviceInfo,
-                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
+                    mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
                     app.getReportedProcState());
             r.postNotification();
             created = true;
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index 1866420..fab967c 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -126,11 +126,6 @@
 
     private final FindTaskResult mTmpFindTaskResult = new FindTaskResult();
 
-    @VisibleForTesting
-    ActivityDisplay(ActivityStackSupervisor supervisor, int displayId) {
-        this(supervisor, supervisor.mDisplayManager.getDisplay(displayId));
-    }
-
     ActivityDisplay(ActivityStackSupervisor supervisor, Display display) {
         mSupervisor = supervisor;
         mDisplayId = display.getDisplayId();
@@ -895,6 +890,8 @@
         mRemoved = true;
 
         releaseSelfIfNeeded();
+
+        mSupervisor.getKeyguardController().onDisplayRemoved(mDisplayId);
     }
 
     private void releaseSelfIfNeeded() {
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 2c8f2fc..3a0289c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -68,6 +68,7 @@
     static final String KEY_BOUND_SERVICE_CRASH_MAX_RETRY = "service_crash_max_retry";
     static final String KEY_PROCESS_START_ASYNC = "process_start_async";
     static final String KEY_MEMORY_INFO_THROTTLE_TIME = "memory_info_throttle_time";
+    static final String KEY_TOP_TO_FGS_GRACE_DURATION = "top_to_fgs_grace_duration";
 
     private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
     private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000;
@@ -97,6 +98,7 @@
     private static final int DEFAULT_BOUND_SERVICE_CRASH_MAX_RETRY = 16;
     private static final boolean DEFAULT_PROCESS_START_ASYNC = true;
     private static final long DEFAULT_MEMORY_INFO_THROTTLE_TIME = 5*60*1000;
+    private static final long DEFAULT_TOP_TO_FGS_GRACE_DURATION = 15 * 1000;
 
     // Maximum number of cached processes we will allow.
     public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES;
@@ -212,6 +214,10 @@
     // throttle requests from apps.
     public long MEMORY_INFO_THROTTLE_TIME = DEFAULT_MEMORY_INFO_THROTTLE_TIME;
 
+    // Allow app just moving from TOP to FOREGROUND_SERVICE to stay in a higher adj value for
+    // this long.
+    public long TOP_TO_FGS_GRACE_DURATION = DEFAULT_TOP_TO_FGS_GRACE_DURATION;
+
     // Indicates whether the activity starts logging is enabled.
     // Controlled by Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED
     boolean mFlagActivityStartsLoggingEnabled;
@@ -355,6 +361,8 @@
                     DEFAULT_PROCESS_START_ASYNC);
             MEMORY_INFO_THROTTLE_TIME = mParser.getLong(KEY_MEMORY_INFO_THROTTLE_TIME,
                     DEFAULT_MEMORY_INFO_THROTTLE_TIME);
+            TOP_TO_FGS_GRACE_DURATION = mParser.getDurationMillis(KEY_TOP_TO_FGS_GRACE_DURATION,
+                    DEFAULT_TOP_TO_FGS_GRACE_DURATION);
 
             updateMaxCachedProcesses();
         }
@@ -438,6 +446,8 @@
         pw.println(FLAG_PROCESS_START_ASYNC);
         pw.print("  "); pw.print(KEY_MEMORY_INFO_THROTTLE_TIME); pw.print("=");
         pw.println(MEMORY_INFO_THROTTLE_TIME);
+        pw.print("  "); pw.print(KEY_TOP_TO_FGS_GRACE_DURATION); pw.print("=");
+        pw.println(TOP_TO_FGS_GRACE_DURATION);
 
         pw.println();
         if (mOverrideMaxCachedProcesses >= 0) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b64e8b8..2fd699e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -134,7 +134,6 @@
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SERVICE;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_UID_OBSERVERS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_URI_PERMISSION;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
@@ -417,7 +416,6 @@
     private static final String TAG_SERVICE = TAG + POSTFIX_SERVICE;
     private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
     private static final String TAG_UID_OBSERVERS = TAG + POSTFIX_UID_OBSERVERS;
-    private static final String TAG_URI_PERMISSION = TAG + POSTFIX_URI_PERMISSION;
 
     // Mock "pretend we're idle now" broadcast action to the job scheduler; declared
     // here so that while the job scheduler can depend on AMS, the other way around
@@ -563,6 +561,7 @@
     String mDeviceOwnerName;
 
     final UserController mUserController;
+    final PendingIntentController mPendingIntentController;
 
     final AppErrors mAppErrors;
 
@@ -665,11 +664,6 @@
     int mNextIsolatedProcessUid = 0;
 
     /**
-     * The currently running heavy-weight process, if any.
-     */
-    ProcessRecord mHeavyWeightProcess = null;
-
-    /**
      * Non-persistent appId whitelist for background restrictions
      */
     int[] mBackgroundAppIdWhitelist = new int[] {
@@ -826,18 +820,6 @@
     final SparseArray<UidRecord> mValidateUids = new SparseArray<>();
 
     /**
-     * Packages that the user has asked to have run in screen size
-     * compatibility mode instead of filling the screen.
-     */
-    final CompatModePackages mCompatModePackages;
-
-    /**
-     * Set of IntentSenderRecord objects that are currently active.
-     */
-    final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
-            = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
-
-    /**
      * Fingerprints (hashCode()) of stack traces that we've
      * already logged DropBox entries for.  Guarded by itself.  If
      * something (rogue user app) forces this over
@@ -1097,11 +1079,10 @@
     volatile boolean mSystemReady = false;
     volatile boolean mOnBattery = false;
     volatile int mFactoryTest;
+    volatile boolean mBooting = false;
 
-    @GuardedBy("this") boolean mBooting = false;
     @GuardedBy("this") boolean mCallFinishBooting = false;
     @GuardedBy("this") boolean mBootAnimationComplete = false;
-    @GuardedBy("this") boolean mLaunchWarningShown = false;
     private @GuardedBy("this") boolean mCheckedForSetup = false;
 
     final Context mContext;
@@ -1388,10 +1369,8 @@
 
     long mLastWriteTime = 0;
 
-    /**
-     * Set to true after the system has finished booting.
-     */
-    boolean mBooted = false;
+    /** Set to true after the system has finished booting. */
+    volatile boolean mBooted = false;
 
     /**
      * Current boot phase.
@@ -1440,9 +1419,6 @@
     static final int UPDATE_TIME_ZONE = 13;
     static final int PROC_START_TIMEOUT_MSG = 20;
     static final int KILL_APPLICATION_MSG = 22;
-    static final int FINALIZE_PENDING_INTENT_MSG = 23;
-    static final int POST_HEAVY_NOTIFICATION_MSG = 24;
-    static final int CANCEL_HEAVY_NOTIFICATION_MSG = 25;
     static final int SHOW_STRICT_MODE_VIOLATION_UI_MSG = 26;
     static final int CHECK_EXCESSIVE_POWER_USE_MSG = 27;
     static final int CLEAR_DNS_CACHE_MSG = 28;
@@ -1451,7 +1427,6 @@
     static final int DISPATCH_PROCESS_DIED_UI_MSG = 32;
     static final int REPORT_MEM_USAGE_MSG = 33;
     static final int UPDATE_TIME_PREFERENCE_MSG = 41;
-    static final int FINISH_BOOTING_MSG = 45;
     static final int SEND_LOCALE_TO_MOUNT_DAEMON_MSG = 47;
     static final int NOTIFY_CLEARTEXT_NETWORK_MSG = 49;
     static final int POST_DUMP_HEAP_NOTIFICATION_MSG = 50;
@@ -1462,7 +1437,6 @@
     static final int IDLE_UIDS_MSG = 58;
     static final int HANDLE_TRUST_STORAGE_UPDATE_MSG = 63;
     static final int SERVICE_FOREGROUND_TIMEOUT_MSG = 66;
-    static final int DISPATCH_PENDING_INTENT_CANCEL_MSG = 67;
     static final int PUSH_TEMP_WHITELIST_UI_MSG = 68;
     static final int SERVICE_FOREGROUND_CRASH_MSG = 69;
     static final int DISPATCH_OOM_ADJ_OBSERVER_MSG = 70;
@@ -1661,21 +1635,6 @@
                 mServices.serviceForegroundCrash(
                     (ProcessRecord) msg.obj, msg.getData().getCharSequence(SERVICE_RECORD_KEY));
             } break;
-            case DISPATCH_PENDING_INTENT_CANCEL_MSG: {
-                RemoteCallbackList<IResultReceiver> callbacks
-                        = (RemoteCallbackList<IResultReceiver>)msg.obj;
-                int N = callbacks.beginBroadcast();
-                for (int i = 0; i < N; i++) {
-                    try {
-                        callbacks.getBroadcastItem(i).send(Activity.RESULT_CANCELED, null);
-                    } catch (RemoteException e) {
-                    }
-                }
-                callbacks.finishBroadcast();
-                // We have to clean up the RemoteCallbackList here, because otherwise it will
-                // needlessly hold the enclosed callbacks until the remote process dies.
-                callbacks.kill();
-            } break;
             case UPDATE_TIME_ZONE: {
                 synchronized (ActivityManagerService.this) {
                     for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
@@ -1755,68 +1714,6 @@
                             false, userId, reason);
                 }
             } break;
-            case FINALIZE_PENDING_INTENT_MSG: {
-                ((PendingIntentRecord)msg.obj).completeFinalize();
-            } break;
-            case POST_HEAVY_NOTIFICATION_MSG: {
-                INotificationManager inm = NotificationManager.getService();
-                if (inm == null) {
-                    return;
-                }
-
-                ActivityRecord root = (ActivityRecord)msg.obj;
-                final WindowProcessController process = root.app;
-                if (process == null) {
-                    return;
-                }
-
-                try {
-                    Context context = mContext.createPackageContext(process.mInfo.packageName, 0);
-                    String text = mContext.getString(R.string.heavy_weight_notification,
-                            context.getApplicationInfo().loadLabel(context.getPackageManager()));
-                    Notification notification =
-                            new Notification.Builder(context,
-                                    SystemNotificationChannels.HEAVY_WEIGHT_APP)
-                            .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
-                            .setWhen(0)
-                            .setOngoing(true)
-                            .setTicker(text)
-                            .setColor(mContext.getColor(
-                                    com.android.internal.R.color.system_notification_accent_color))
-                            .setContentTitle(text)
-                            .setContentText(
-                                    mContext.getText(R.string.heavy_weight_notification_detail))
-                            .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0,
-                                    root.intent, PendingIntent.FLAG_CANCEL_CURRENT, null,
-                                    new UserHandle(root.userId)))
-                            .build();
-                    try {
-                        inm.enqueueNotificationWithTag("android", "android", null,
-                                SystemMessage.NOTE_HEAVY_WEIGHT_NOTIFICATION,
-                                notification, root.userId);
-                    } catch (RuntimeException e) {
-                        Slog.w(ActivityManagerService.TAG,
-                                "Error showing notification for heavy-weight app", e);
-                    } catch (RemoteException e) {
-                    }
-                } catch (NameNotFoundException e) {
-                    Slog.w(TAG, "Unable to create context for heavy notification", e);
-                }
-            } break;
-            case CANCEL_HEAVY_NOTIFICATION_MSG: {
-                INotificationManager inm = NotificationManager.getService();
-                if (inm == null) {
-                    return;
-                }
-                try {
-                    inm.cancelNotificationWithTag("android", null,
-                            SystemMessage.NOTE_HEAVY_WEIGHT_NOTIFICATION, msg.arg1);
-                } catch (RuntimeException e) {
-                    Slog.w(ActivityManagerService.TAG,
-                            "Error canceling notification for service", e);
-                } catch (RemoteException e) {
-                }
-            } break;
             case CHECK_EXCESSIVE_POWER_USE_MSG: {
                 synchronized (ActivityManagerService.this) {
                     checkExcessivePowerUsageLocked();
@@ -1853,17 +1750,6 @@
                 }
                 break;
             }
-            case FINISH_BOOTING_MSG: {
-                if (msg.arg1 != 0) {
-                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "FinishBooting");
-                    finishBooting();
-                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-                }
-                if (msg.arg2 != 0) {
-                    mAtmInternal.enableScreenAfterBoot(mBooted);
-                }
-                break;
-            }
             case SEND_LOCALE_TO_MOUNT_DAEMON_MSG: {
                 try {
                     Locale l = (Locale) msg.obj;
@@ -2430,7 +2316,6 @@
         mAppErrors = null;
         mAppOpsService = mInjector.getAppOpsService(null, null);
         mBatteryStatsService = null;
-        mCompatModePackages = null;
         mConstants = null;
         mHandler = null;
         mHandlerThread = null;
@@ -2442,6 +2327,7 @@
         mSystemThread = null;
         mUiHandler = injector.getUiHandler(null);
         mUserController = null;
+        mPendingIntentController = null;
         mProcStartHandlerThread = null;
         mProcStartHandler = null;
         mHiddenApiBlacklist = null;
@@ -2495,7 +2381,8 @@
         final File systemDir = SystemServiceManager.ensureSystemDir();
 
         // TODO: Move creation of battery stats service outside of activity manager service.
-        mBatteryStatsService = new BatteryStatsService(systemContext, systemDir, mHandler);
+        mBatteryStatsService = new BatteryStatsService(systemContext, systemDir,
+                BackgroundThread.get().getHandler());
         mBatteryStatsService.getActiveStatistics().readLocked();
         mBatteryStatsService.scheduleWriteToDisk();
         mOnBattery = DEBUG_POWER ? true
@@ -2519,7 +2406,6 @@
         }
 
         mTrackingAssociations = "1".equals(SystemProperties.get("debug.track-associations"));
-        mCompatModePackages = new CompatModePackages(this, systemDir, mHandler);
         mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
 
         mActivityTaskManager = atm;
@@ -2527,6 +2413,9 @@
         mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
         mStackSupervisor = mActivityTaskManager.mStackSupervisor;
 
+        mPendingIntentController = new PendingIntentController(
+                mHandlerThread.getLooper(), mUserController);
+
         mProcessCpuThread = new Thread("CpuTracker") {
             @Override
             public void run() {
@@ -2597,6 +2486,7 @@
         LocalServices.addService(ActivityManagerInternal.class, new LocalService());
         mActivityTaskManager.onActivityManagerInternalAdded();
         mUgmInternal.onActivityManagerInternalAdded();
+        mPendingIntentController.onActivityManagerInternalAdded();
         // Wait for the synchronized block started in mProcessCpuThread,
         // so that any other access to mProcessCpuTracker from main thread
         // will be blocked during mProcessCpuTracker initialization.
@@ -3791,31 +3681,31 @@
         return true;
     }
 
-    void updateUsageStats(ActivityRecord component, boolean resumed) {
+    void updateUsageStats(ComponentName activity, int uid, int userId, boolean resumed) {
         if (DEBUG_SWITCH) Slog.d(TAG_SWITCH,
-                "updateUsageStats: comp=" + component + "res=" + resumed);
+                "updateUsageStats: comp=" + activity + "res=" + resumed);
         final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
         StatsLog.write(StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED,
-            component.app.mUid, component.realActivity.getPackageName(),
-            component.realActivity.getShortClassName(), resumed ?
+            uid, activity.getPackageName(),
+            activity.getShortClassName(), resumed ?
                         StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__STATE__FOREGROUND :
                         StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__STATE__BACKGROUND);
         if (resumed) {
             if (mUsageStatsService != null) {
-                mUsageStatsService.reportEvent(component.realActivity, component.userId,
+                mUsageStatsService.reportEvent(activity, userId,
                         UsageEvents.Event.MOVE_TO_FOREGROUND);
 
             }
             synchronized (stats) {
-                stats.noteActivityResumedLocked(component.app.mUid);
+                stats.noteActivityResumedLocked(uid);
             }
         } else {
             if (mUsageStatsService != null) {
-                mUsageStatsService.reportEvent(component.realActivity, component.userId,
+                mUsageStatsService.reportEvent(activity, userId,
                         UsageEvents.Event.MOVE_TO_BACKGROUND);
             }
             synchronized (stats) {
-                stats.noteActivityPausedLocked(component.app.mUid);
+                stats.noteActivityPausedLocked(uid);
             }
         }
     }
@@ -3895,8 +3785,8 @@
         mCheckedForSetup = checked;
     }
 
-    CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) {
-        return mCompatModePackages.compatibilityInfoForPackageLocked(ai);
+    CompatibilityInfo compatibilityInfoForPackage(ApplicationInfo ai) {
+        return mAtmInternal.compatibilityInfoForPackage(ai);
     }
 
     private void enforceNotIsolatedCaller(String caller) {
@@ -3906,37 +3796,8 @@
     }
 
     @Override
-    public int getPackageScreenCompatMode(String packageName) {
-        enforceNotIsolatedCaller("getPackageScreenCompatMode");
-        synchronized (this) {
-            return mCompatModePackages.getPackageScreenCompatModeLocked(packageName);
-        }
-    }
-
-    @Override
     public void setPackageScreenCompatMode(String packageName, int mode) {
-        enforceCallingPermission(android.Manifest.permission.SET_SCREEN_COMPATIBILITY,
-                "setPackageScreenCompatMode");
-        synchronized (this) {
-            mCompatModePackages.setPackageScreenCompatModeLocked(packageName, mode);
-        }
-    }
-
-    @Override
-    public boolean getPackageAskScreenCompat(String packageName) {
-        enforceNotIsolatedCaller("getPackageAskScreenCompat");
-        synchronized (this) {
-            return mCompatModePackages.getPackageAskCompatModeLocked(packageName);
-        }
-    }
-
-    @Override
-    public void setPackageAskScreenCompat(String packageName, boolean ask) {
-        enforceCallingPermission(android.Manifest.permission.SET_SCREEN_COMPATIBILITY,
-                "setPackageAskScreenCompat");
-        synchronized (this) {
-            mCompatModePackages.setPackageAskCompatModeLocked(packageName, ask);
-        }
+        mActivityTaskManager.setPackageScreenCompatMode(packageName, mode);
     }
 
     private boolean hasUsageStatsPermission(String callingPackage) {
@@ -4307,19 +4168,7 @@
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
-
-        synchronized(this) {
-            final ProcessRecord proc = mHeavyWeightProcess;
-            if (proc == null) {
-                return;
-            }
-
-            proc.getWindowProcessController().finishActivities();
-
-            mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,
-                    proc.userId, 0));
-            mHeavyWeightProcess = null;
-        }
+        mAtmInternal.finishHeavyWeightApp();
     }
 
     @Override
@@ -5641,55 +5490,8 @@
         }
 
         if (packageName == null || uninstalling) {
-            // Remove pending intents.  For now we only do this when force
-            // stopping users, because we have some problems when doing this
-            // for packages -- app widgets are not currently cleaned up for
-            // such packages, so they can be left with bad pending intents.
-            if (mIntentSenderRecords.size() > 0) {
-                Iterator<WeakReference<PendingIntentRecord>> it
-                        = mIntentSenderRecords.values().iterator();
-                while (it.hasNext()) {
-                    WeakReference<PendingIntentRecord> wpir = it.next();
-                    if (wpir == null) {
-                        it.remove();
-                        continue;
-                    }
-                    PendingIntentRecord pir = wpir.get();
-                    if (pir == null) {
-                        it.remove();
-                        continue;
-                    }
-                    if (packageName == null) {
-                        // Stopping user, remove all objects for the user.
-                        if (pir.key.userId != userId) {
-                            // Not the same user, skip it.
-                            continue;
-                        }
-                    } else {
-                        if (UserHandle.getAppId(pir.uid) != appId) {
-                            // Different app id, skip it.
-                            continue;
-                        }
-                        if (userId != UserHandle.USER_ALL && pir.key.userId != userId) {
-                            // Different user, skip it.
-                            continue;
-                        }
-                        if (!pir.key.packageName.equals(packageName)) {
-                            // Different package, skip it.
-                            continue;
-                        }
-                    }
-                    if (!doit) {
-                        return true;
-                    }
-                    didSomething = true;
-                    it.remove();
-                    makeIntentSenderCanceledLocked(pir);
-                    if (pir.key.activity != null && pir.key.activity.pendingResults != null) {
-                        pir.key.activity.pendingResults.remove(pir.ref);
-                    }
-                }
-            }
+            didSomething |= mPendingIntentController.removePendingIntentsForPackage(
+                    packageName, userId, appId, doit);
         }
 
         if (doit) {
@@ -5789,11 +5591,8 @@
             return false;
         }
         removeProcessNameLocked(name, uid);
-        if (mHeavyWeightProcess == app) {
-            mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,
-                    mHeavyWeightProcess.userId, 0));
-            mHeavyWeightProcess = null;
-        }
+        mAtmInternal.clearHeavyWeightProcessIfEquals(app.getWindowProcessController());
+
         boolean needRestart = false;
         if ((app.pid > 0 && app.pid != MY_PID) || (app.pid == 0 && app.pendingStart)) {
             int pid = app.pid;
@@ -5851,11 +5650,7 @@
             EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, app.userId,
                     pid, app.uid, app.processName);
             removeProcessNameLocked(app.processName, app.uid);
-            if (mHeavyWeightProcess == app) {
-                mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,
-                        mHeavyWeightProcess.userId, 0));
-                mHeavyWeightProcess = null;
-            }
+            mAtmInternal.clearHeavyWeightProcessIfEquals(app.getWindowProcessController());
             mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
             // Take care of any launching providers waiting for this process.
             cleanupAppInLaunchingProvidersLocked(app, true);
@@ -6032,9 +5827,10 @@
                                  PackageManager.NOTIFY_PACKAGE_USE_INSTRUMENTATION);
             }
             if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Binding proc "
-                    + processName + " with config " + getGlobalConfiguration());
+                    + processName + " with config "
+                    + app.getWindowProcessController().getConfiguration());
             ApplicationInfo appInfo = instr != null ? instr.mTargetInfo : app.info;
-            app.compat = compatibilityInfoForPackageLocked(appInfo);
+            app.compat = compatibilityInfoForPackage(appInfo);
 
             ProfilerInfo profilerInfo = null;
             String preBindAgent = null;
@@ -6145,8 +5941,8 @@
                         instr2.mUiAutomationConnection, testMode,
                         mBinderTransactionTrackingEnabled, enableTrackAllocation,
                         isRestrictedBackupMode || !normalMode, app.isPersistent(),
-                        new Configuration(getGlobalConfiguration()), app.compat,
-                        getCommonServicesLocked(app.isolated),
+                        new Configuration(app.getWindowProcessController().getConfiguration()),
+                        app.compat, getCommonServicesLocked(app.isolated),
                         mCoreSettingsObserver.getCoreSettingsLocked(),
                         buildSerial, isAutofillCompatEnabled);
             } else {
@@ -6154,8 +5950,8 @@
                         null, null, null, testMode,
                         mBinderTransactionTrackingEnabled, enableTrackAllocation,
                         isRestrictedBackupMode || !normalMode, app.isPersistent(),
-                        new Configuration(getGlobalConfiguration()), app.compat,
-                        getCommonServicesLocked(app.isolated),
+                        new Configuration(app.getWindowProcessController().getConfiguration()),
+                        app.compat, getCommonServicesLocked(app.isolated),
                         mCoreSettingsObserver.getCoreSettingsLocked(),
                         buildSerial, isAutofillCompatEnabled);
             }
@@ -6231,7 +6027,7 @@
                              PackageManager.NOTIFY_PACKAGE_USE_BACKUP);
             try {
                 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo,
-                        compatibilityInfoForPackageLocked(mBackupTarget.appInfo),
+                        compatibilityInfoForPackage(mBackupTarget.appInfo),
                         mBackupTarget.backupMode);
             } catch (Exception e) {
                 Slog.wtf(TAG, "Exception thrown creating backup agent in " + app, e);
@@ -6264,11 +6060,6 @@
         }
     }
 
-    void postFinishBooting(boolean finishBooting, boolean enableScreen) {
-        mHandler.sendMessage(mHandler.obtainMessage(FINISH_BOOTING_MSG,
-                finishBooting ? 1 : 0, enableScreen ? 1 : 0));
-    }
-
     @Override
     public void showBootMessage(final CharSequence msg, final boolean always) {
         if (Binder.getCallingUid() != myUid()) {
@@ -6278,6 +6069,8 @@
     }
 
     final void finishBooting() {
+        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "FinishBooting");
+
         synchronized (this) {
             if (!mBootAnimationComplete) {
                 mCallFinishBooting = true;
@@ -6383,6 +6176,8 @@
                     });
             mUserController.scheduleStartProfiles();
         }
+
+        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
     }
 
     @Override
@@ -6393,9 +6188,7 @@
             mBootAnimationComplete = true;
         }
         if (callFinishBooting) {
-            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "FinishBooting");
             finishBooting();
-            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
         }
     }
 
@@ -6410,9 +6203,7 @@
         }
 
         if (booting) {
-            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "FinishBooting");
             finishBooting();
-            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
         }
 
         if (enableScreen) {
@@ -6483,90 +6274,19 @@
                     }
                 }
 
-                return getIntentSenderLocked(type, packageName, callingUid, userId,
-                        token, resultWho, requestCode, intents, resolvedTypes, flags, bOptions);
-
+                if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) {
+                    return mAtmInternal.getIntentSender(type, packageName, callingUid, userId,
+                            token, resultWho, requestCode, intents, resolvedTypes, flags, bOptions);
+                }
+                return mPendingIntentController.getIntentSender(type, packageName, callingUid,
+                        userId, token, resultWho, requestCode, intents, resolvedTypes, flags,
+                        bOptions);
             } catch (RemoteException e) {
                 throw new SecurityException(e);
             }
         }
     }
 
-    IIntentSender getIntentSenderLocked(int type, String packageName,
-            int callingUid, int userId, IBinder token, String resultWho,
-            int requestCode, Intent[] intents, String[] resolvedTypes, int flags,
-            Bundle bOptions) {
-        if (DEBUG_MU) Slog.v(TAG_MU, "getIntentSenderLocked(): uid=" + callingUid);
-        ActivityRecord activity = null;
-        if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) {
-            activity = ActivityRecord.isInStackLocked(token);
-            if (activity == null) {
-                Slog.w(TAG, "Failed createPendingResult: activity " + token + " not in any stack");
-                return null;
-            }
-            if (activity.finishing) {
-                Slog.w(TAG, "Failed createPendingResult: activity " + activity + " is finishing");
-                return null;
-            }
-        }
-
-        // We're going to be splicing together extras before sending, so we're
-        // okay poking into any contained extras.
-        if (intents != null) {
-            for (int i = 0; i < intents.length; i++) {
-                intents[i].setDefusable(true);
-            }
-        }
-        Bundle.setDefusable(bOptions, true);
-
-        final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
-        final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
-        final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
-        flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
-                |PendingIntent.FLAG_UPDATE_CURRENT);
-
-        PendingIntentRecord.Key key = new PendingIntentRecord.Key(type, packageName, activity,
-                resultWho, requestCode, intents, resolvedTypes, flags,
-                SafeActivityOptions.fromBundle(bOptions), userId);
-        WeakReference<PendingIntentRecord> ref;
-        ref = mIntentSenderRecords.get(key);
-        PendingIntentRecord rec = ref != null ? ref.get() : null;
-        if (rec != null) {
-            if (!cancelCurrent) {
-                if (updateCurrent) {
-                    if (rec.key.requestIntent != null) {
-                        rec.key.requestIntent.replaceExtras(intents != null ?
-                                intents[intents.length - 1] : null);
-                    }
-                    if (intents != null) {
-                        intents[intents.length-1] = rec.key.requestIntent;
-                        rec.key.allIntents = intents;
-                        rec.key.allResolvedTypes = resolvedTypes;
-                    } else {
-                        rec.key.allIntents = null;
-                        rec.key.allResolvedTypes = null;
-                    }
-                }
-                return rec;
-            }
-            makeIntentSenderCanceledLocked(rec);
-            mIntentSenderRecords.remove(key);
-        }
-        if (noCreate) {
-            return rec;
-        }
-        rec = new PendingIntentRecord(this, key, callingUid);
-        mIntentSenderRecords.put(key, rec.ref);
-        if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) {
-            if (activity.pendingResults == null) {
-                activity.pendingResults
-                        = new HashSet<WeakReference<PendingIntentRecord>>();
-            }
-            activity.pendingResults.add(rec.ref);
-        }
-        return rec;
-    }
-
     @Override
     public int sendIntentSender(IIntentSender target, IBinder whitelistToken, int code,
             Intent intent, String resolvedType,
@@ -6606,44 +6326,7 @@
 
     @Override
     public void cancelIntentSender(IIntentSender sender) {
-        if (!(sender instanceof PendingIntentRecord)) {
-            return;
-        }
-        synchronized(this) {
-            PendingIntentRecord rec = (PendingIntentRecord)sender;
-            try {
-                final int uid = AppGlobals.getPackageManager().getPackageUid(rec.key.packageName,
-                        MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getCallingUserId());
-                if (!UserHandle.isSameApp(uid, Binder.getCallingUid())) {
-                    String msg = "Permission Denial: cancelIntentSender() from pid="
-                        + Binder.getCallingPid()
-                        + ", uid=" + Binder.getCallingUid()
-                        + " is not allowed to cancel package "
-                        + rec.key.packageName;
-                    Slog.w(TAG, msg);
-                    throw new SecurityException(msg);
-                }
-            } catch (RemoteException e) {
-                throw new SecurityException(e);
-            }
-            cancelIntentSenderLocked(rec, true);
-        }
-    }
-
-    void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
-        makeIntentSenderCanceledLocked(rec);
-        mIntentSenderRecords.remove(rec.key);
-        if (cleanActivity && rec.key.activity != null) {
-            rec.key.activity.pendingResults.remove(rec.ref);
-        }
-    }
-
-    void makeIntentSenderCanceledLocked(PendingIntentRecord rec) {
-        rec.canceled = true;
-        RemoteCallbackList<IResultReceiver> callbacks = rec.detachCancelListenersLocked();
-        if (callbacks != null) {
-            mHandler.obtainMessage(DISPATCH_PENDING_INTENT_CANCEL_MSG, callbacks).sendToTarget();
-        }
+        mPendingIntentController.cancelIntentSender(sender);
     }
 
     @Override
@@ -8406,10 +8089,17 @@
         }
     }
 
+    /** @deprecated - Use {@link #removeContentProviderExternalAsUser} which takes a user ID. */
+    @Deprecated
+    @Override
     public void removeContentProviderExternal(String name, IBinder token) {
+        removeContentProviderExternalAsUser(name, token, UserHandle.getCallingUserId());
+    }
+
+    @Override
+    public void removeContentProviderExternalAsUser(String name, IBinder token, int userId) {
         enforceCallingPermission(android.Manifest.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY,
             "Do not have permission in call removeContentProviderExternal()");
-        int userId = UserHandle.getCallingUserId();
         long ident = Binder.clearCallingIdentity();
         try {
             removeContentProviderExternalUnchecked(name, token, userId);
@@ -8853,7 +8543,7 @@
             StatsLog.write(StatsLog.ISOLATED_UID_CHANGED, info.uid, uid,
                     StatsLog.ISOLATED_UID_CHANGED__EVENT__CREATED);
         }
-        final ProcessRecord r = new ProcessRecord(this, info, proc, uid);
+        final ProcessRecord r = new ProcessRecord(this, info, proc, uid, getGlobalConfiguration());
         if (!mBooted && !mBooting
                 && userId == UserHandle.USER_SYSTEM
                 && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
@@ -9741,9 +9431,10 @@
 
         mBatteryStatsService.noteWakupAlarm(sourcePkg, sourceUid, workSource, tag);
         if (workSource != null) {
-            StatsLog.write(StatsLog.WAKEUP_ALARM_OCCURRED, workSource, tag);
+            StatsLog.write(StatsLog.WAKEUP_ALARM_OCCURRED, workSource, tag, sourcePkg);
         } else {
-            StatsLog.write_non_chained(StatsLog.WAKEUP_ALARM_OCCURRED, sourceUid, null, tag);
+            StatsLog.write_non_chained(StatsLog.WAKEUP_ALARM_OCCURRED, sourceUid, null, tag,
+                    sourcePkg);
         }
     }
 
@@ -10845,7 +10536,7 @@
             int clientTargetSdk) {
         outInfo.pid = app.pid;
         outInfo.uid = app.info.uid;
-        if (mHeavyWeightProcess == app) {
+        if (mAtmInternal.isHeavyWeightProcess(app.getWindowProcessController())) {
             outInfo.flags |= ActivityManager.RunningAppProcessInfo.FLAG_CANT_SAVE_STATE;
         }
         if (app.isPersistent()) {
@@ -11000,7 +10691,7 @@
                 pw.println("-------------------------------------------------------------------------------");
 
             }
-            dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll, dumpPackage);
+            mPendingIntentController.dumpPendingIntents(pw, dumpAll, dumpPackage);
             pw.println();
             if (dumpAll) {
                 pw.println("-------------------------------------------------------------------------------");
@@ -11293,7 +10984,7 @@
                     opti++;
                 }
                 synchronized (this) {
-                    dumpPendingIntentsLocked(fd, pw, args, opti, true, dumpPackage);
+                    mPendingIntentController.dumpPendingIntents(pw, true, dumpPackage);
                 }
             } else if ("processes".equals(cmd) || "p".equals(cmd)) {
                 if (opti < args.length) {
@@ -11888,13 +11579,13 @@
             TimeUtils.formatDuration(mActivityTaskManager.mPreviousProcessVisibleTime, sb);
             pw.println(sb);
         }
-        if (mHeavyWeightProcess != null && (dumpPackage == null
-                || mHeavyWeightProcess.pkgList.containsKey(dumpPackage))) {
+        if (mActivityTaskManager.mHeavyWeightProcess != null && (dumpPackage == null
+                || mActivityTaskManager.mHeavyWeightProcess.mPkgList.contains(dumpPackage))) {
             if (needSep) {
                 pw.println();
                 needSep = false;
             }
-            pw.println("  mHeavyWeightProcess: " + mHeavyWeightProcess);
+            pw.println("  mHeavyWeightProcess: " + mActivityTaskManager.mHeavyWeightProcess);
         }
         if (dumpAll && mPendingStarts.size() > 0) {
             if (needSep) pw.println();
@@ -11913,10 +11604,10 @@
                 pw.println("  mConfigWillChange: "
                         + mActivityTaskManager.getTopDisplayFocusedStack().mConfigWillChange);
             }
-            if (mCompatModePackages.getPackages().size() > 0) {
+            if (mActivityTaskManager.mCompatModePackages.getPackages().size() > 0) {
                 boolean printed = false;
                 for (Map.Entry<String, Integer> entry
-                        : mCompatModePackages.getPackages().entrySet()) {
+                        : mActivityTaskManager.mCompatModePackages.getPackages().entrySet()) {
                     String pkg = entry.getKey();
                     int mode = entry.getValue();
                     if (dumpPackage != null && !dumpPackage.equals(pkg)) {
@@ -12298,12 +11989,13 @@
             proto.write(ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC_VISIBLE_TIME_MS, mActivityTaskManager.mPreviousProcessVisibleTime);
         }
 
-        if (mHeavyWeightProcess != null && (dumpPackage == null
-                || mHeavyWeightProcess.pkgList.containsKey(dumpPackage))) {
-            mHeavyWeightProcess.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.HEAVY_WEIGHT_PROC);
+        if (mActivityTaskManager.mHeavyWeightProcess != null && (dumpPackage == null
+                || mActivityTaskManager.mHeavyWeightProcess.mPkgList.contains(dumpPackage))) {
+            ((ProcessRecord) mActivityTaskManager.mHeavyWeightProcess.mOwner).writeToProto(proto, ActivityManagerServiceDumpProcessesProto.HEAVY_WEIGHT_PROC);
         }
 
-        for (Map.Entry<String, Integer> entry : mCompatModePackages.getPackages().entrySet()) {
+        for (Map.Entry<String, Integer> entry
+                : mActivityTaskManager.mCompatModePackages.getPackages().entrySet()) {
             String pkg = entry.getKey();
             int mode = entry.getValue();
             if (dumpPackage == null || dumpPackage.equals(pkg)) {
@@ -12556,8 +12248,8 @@
         pw.println();
         pw.println("  mHomeProcess: " + mActivityTaskManager.mHomeProcess);
         pw.println("  mPreviousProcess: " + mActivityTaskManager.mPreviousProcess);
-        if (mHeavyWeightProcess != null) {
-            pw.println("  mHeavyWeightProcess: " + mHeavyWeightProcess);
+        if (mActivityTaskManager.mHeavyWeightProcess != null) {
+            pw.println("  mHeavyWeightProcess: " + mActivityTaskManager.mHeavyWeightProcess);
         }
 
         return true;
@@ -12990,61 +12682,6 @@
         mUgmInternal.dump(pw, dumpAll, dumpPackage);
     }
 
-    void dumpPendingIntentsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
-            int opti, boolean dumpAll, String dumpPackage) {
-        boolean printed = false;
-
-        pw.println("ACTIVITY MANAGER PENDING INTENTS (dumpsys activity intents)");
-
-        if (mIntentSenderRecords.size() > 0) {
-            // Organize these by package name, so they are easier to read.
-            final ArrayMap<String, ArrayList<PendingIntentRecord>> byPackage = new ArrayMap<>();
-            final ArrayList<WeakReference<PendingIntentRecord>> weakRefs = new ArrayList<>();
-            final Iterator<WeakReference<PendingIntentRecord>> it
-                    = mIntentSenderRecords.values().iterator();
-            while (it.hasNext()) {
-                WeakReference<PendingIntentRecord> ref = it.next();
-                PendingIntentRecord rec = ref != null ? ref.get() : null;
-                if (rec == null) {
-                    weakRefs.add(ref);
-                    continue;
-                }
-                if (dumpPackage != null && !dumpPackage.equals(rec.key.packageName)) {
-                    continue;
-                }
-                ArrayList<PendingIntentRecord> list = byPackage.get(rec.key.packageName);
-                if (list == null) {
-                    list = new ArrayList<>();
-                    byPackage.put(rec.key.packageName, list);
-                }
-                list.add(rec);
-            }
-            for (int i = 0; i < byPackage.size(); i++) {
-                ArrayList<PendingIntentRecord> intents = byPackage.valueAt(i);
-                printed = true;
-                pw.print("  * "); pw.print(byPackage.keyAt(i));
-                pw.print(": "); pw.print(intents.size()); pw.println(" items");
-                for (int j = 0; j < intents.size(); j++) {
-                    pw.print("    #"); pw.print(j); pw.print(": "); pw.println(intents.get(j));
-                    if (dumpAll) {
-                        intents.get(j).dump(pw, "      ");
-                    }
-                }
-            }
-            if (weakRefs.size() > 0) {
-                printed = true;
-                pw.println("  * WEAK REFS:");
-                for (int i = 0; i < weakRefs.size(); i++) {
-                    pw.print("    #"); pw.print(i); pw.print(": "); pw.println(weakRefs.get(i));
-                }
-            }
-        }
-
-        if (!printed) {
-            pw.println("  (nothing)");
-        }
-    }
-
     private static final int dumpProcessList(PrintWriter pw,
             ActivityManagerService service, List list,
             String prefix, String normalLabel, String persistentLabel,
@@ -15189,11 +14826,7 @@
             if (!replacingPid) {
                 removeProcessNameLocked(app.processName, app.uid, app);
             }
-            if (mHeavyWeightProcess == app) {
-                mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,
-                        mHeavyWeightProcess.userId, 0));
-                mHeavyWeightProcess = null;
-            }
+            mAtmInternal.clearHeavyWeightProcessIfEquals(app.getWindowProcessController());
         } else if (!app.removed) {
             // This app is persistent, so we need to keep its record around.
             // If it is not already on the pending app list, add it there
@@ -15323,24 +14956,6 @@
         }
     }
 
-    ComponentName startServiceInPackage(int uid, Intent service, String resolvedType,
-            boolean fgRequired, String callingPackage, int userId)
-            throws TransactionTooLargeException {
-        synchronized(this) {
-            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
-                    "startServiceInPackage: " + service + " type=" + resolvedType);
-            final long origId = Binder.clearCallingIdentity();
-            ComponentName res;
-            try {
-                res = mServices.startServiceLocked(null, service,
-                        resolvedType, -1, uid, fgRequired, callingPackage, userId);
-            } finally {
-                Binder.restoreCallingIdentity(origId);
-            }
-            return res;
-        }
-    }
-
     @Override
     public int stopService(IApplicationThread caller, Intent service,
             String resolvedType, int userId) {
@@ -15577,7 +15192,7 @@
                 if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "Agent proc already running: " + proc);
                 try {
                     proc.thread.scheduleCreateBackupAgent(app,
-                            compatibilityInfoForPackageLocked(app), backupMode);
+                            compatibilityInfoForPackage(app), backupMode);
                 } catch (RemoteException e) {
                     // Will time out on the backup manager side
                 }
@@ -15676,7 +15291,7 @@
                 if (proc.thread != null) {
                     try {
                         proc.thread.scheduleDestroyBackupAgent(appInfo,
-                                compatibilityInfoForPackageLocked(appInfo));
+                                compatibilityInfoForPackage(appInfo));
                     } catch (Exception e) {
                         Slog.e(TAG, "Exception when unbinding backup agent:");
                         e.printStackTrace();
@@ -16385,7 +16000,6 @@
 
                                         mServices.forceStopPackageLocked(ssp, userId);
                                         mAtmInternal.onPackageUninstalled(ssp);
-                                        mCompatModePackages.handlePackageUninstalledLocked(ssp);
                                         mBatteryStatsService.notePackageUninstalled(ssp);
                                     }
                                 } else {
@@ -16447,7 +16061,7 @@
                     if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
                         final boolean replacing =
                                 intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
-                        mCompatModePackages.handlePackageAddedLocked(ssp, replacing);
+                        mAtmInternal.onPackageAdded(ssp, replacing);
 
                         try {
                             ApplicationInfo ai = AppGlobals.getPackageManager().
@@ -16464,7 +16078,6 @@
                     Uri data = intent.getData();
                     String ssp;
                     if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
-                        mCompatModePackages.handlePackageDataClearedLocked(ssp);
                         mAtmInternal.onPackageDataCleared(ssp);
                     }
                     break;
@@ -17222,30 +16835,6 @@
         }
     }
 
-    // =========================================================
-    // CONFIGURATION
-    // =========================================================
-
-    public ConfigurationInfo getDeviceConfigurationInfo() {
-        ConfigurationInfo config = new ConfigurationInfo();
-        synchronized (this) {
-            final Configuration globalConfig = getGlobalConfiguration();
-            config.reqTouchScreen = globalConfig.touchscreen;
-            config.reqKeyboardType = globalConfig.keyboard;
-            config.reqNavigation = globalConfig.navigation;
-            if (globalConfig.navigation == Configuration.NAVIGATION_DPAD
-                    || globalConfig.navigation == Configuration.NAVIGATION_TRACKBALL) {
-                config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
-            }
-            if (globalConfig.keyboard != Configuration.KEYBOARD_UNDEFINED
-                    && globalConfig.keyboard != Configuration.KEYBOARD_NOKEYS) {
-                config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
-            }
-            config.reqGlEsVersion = GL_ES_VERSION;
-        }
-        return config;
-    }
-
     @Override
     public StackInfo getFocusedStackInfo() throws RemoteException {
         return mActivityTaskManager.getFocusedStackInfo();
@@ -17778,6 +17367,19 @@
             }
         }
 
+        // If the app was recently in the foreground and moved to a foreground service status,
+        // allow it to get a higher rank in memory for some time, compared to other foreground
+        // services so that it can finish performing any persistence/processing of in-memory state.
+        if (app.hasForegroundServices() && adj > ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ
+                && (app.lastTopTime + mConstants.TOP_TO_FGS_GRACE_DURATION > now
+                    || app.setProcState <= ActivityManager.PROCESS_STATE_TOP)) {
+            adj = ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ;
+            app.adjType = "fg-service-act";
+            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to recent fg: " + app);
+            }
+        }
+
         if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
                 || procState > ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND) {
             if (app.forcingToImportant != null) {
@@ -17796,7 +17398,7 @@
             }
         }
 
-        if (app == mHeavyWeightProcess) {
+        if (mAtmInternal.isHeavyWeightProcess(app.getWindowProcessController())) {
             if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ) {
                 // We don't want to kill the current heavy-weight process.
                 adj = ProcessList.HEAVY_WEIGHT_APP_ADJ;
@@ -18045,6 +17647,10 @@
                                         cr.trackProcState(procState, mAdjSeq, now);
                                         trackedProcState = true;
                                     }
+                                } else if ((cr.flags & Context.BIND_ADJUST_BELOW_PERCEPTIBLE) != 0
+                                        && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
+                                        && adj > ProcessList.PERCEPTIBLE_APP_ADJ + 1) {
+                                    newAdj = ProcessList.PERCEPTIBLE_APP_ADJ + 1;
                                 } else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0
                                         && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
                                         && adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
@@ -19044,6 +18650,8 @@
             // Must be called before updating setProcState
             maybeUpdateUsageStatsLocked(app, nowElapsed);
 
+            maybeUpdateLastTopTime(app, now);
+
             app.setProcState = app.curProcState;
             if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) {
                 app.notCachedSinceIdle = false;
@@ -19268,6 +18876,13 @@
         }
     }
 
+    private void maybeUpdateLastTopTime(ProcessRecord app, long nowUptime) {
+        if (app.setProcState <= ActivityManager.PROCESS_STATE_TOP
+                && app.curProcState > ActivityManager.PROCESS_STATE_TOP) {
+            app.lastTopTime = nowUptime;
+        }
+    }
+
     private final void setProcessTrackerStateLocked(ProcessRecord proc, int memFactor, long now) {
         if (proc.thread != null && proc.baseProcessTracker != null) {
             proc.baseProcessTracker.setState(
@@ -21029,7 +20644,8 @@
                                     memoryStat.pgmajfault,
                                     memoryStat.rssInBytes,
                                     memoryStat.cacheInBytes,
-                                    memoryStat.swapInBytes);
+                                    memoryStat.swapInBytes,
+                                    memoryStat.rssHighWatermarkInBytes);
                     processMemoryStates.add(processMemoryState);
                 }
             }
@@ -21064,18 +20680,6 @@
             ActivityManagerService.this.trimApplications();
         }
 
-        public int getPackageScreenCompatMode(ApplicationInfo ai) {
-            synchronized (ActivityManagerService.this) {
-                return mCompatModePackages.computeCompatModeLocked(ai);
-            }
-        }
-
-        public void setPackageScreenCompatMode(ApplicationInfo ai, int mode) {
-            synchronized (ActivityManagerService.this) {
-                mCompatModePackages.setPackageScreenCompatModeLocked(ai, mode);
-            }
-        }
-
         public void closeSystemDialogs(String reason) {
             ActivityManagerService.this.closeSystemDialogs(reason);
         }
@@ -21124,6 +20728,38 @@
         }
 
         @Override
+        public void updateCpuStats() {
+            synchronized (ActivityManagerService.this) {
+                ActivityManagerService.this.updateCpuStats();
+            }
+        }
+
+        @Override
+        public void updateUsageStats(ComponentName activity, int uid, int userId, boolean resumed) {
+            synchronized (ActivityManagerService.this) {
+                ActivityManagerService.this.updateUsageStats(activity, uid, userId, resumed);
+            }
+        }
+
+        @Override
+        public void updateForegroundTimeIfOnBattery(
+                String packageName, int uid, long cpuTimeDiff) {
+            synchronized (ActivityManagerService.this) {
+                if (!mBatteryStatsService.isOnBattery()) {
+                    return;
+                }
+                final BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
+                synchronized (bsi) {
+                    final BatteryStatsImpl.Uid.Proc ps =
+                            bsi.getProcessStatsLocked(uid, packageName);
+                    if (ps != null) {
+                        ps.addForegroundTimeLocked(cpuTimeDiff);
+                    }
+                }
+            }
+        }
+
+        @Override
         public void sendForegroundProfileChanged(int userId) {
             mUserController.sendForegroundProfileChanged(userId);
         }
@@ -21183,6 +20819,71 @@
                 return ActivityManagerService.this.getTaskForActivity(token, onlyRoot);
             }
         }
+
+        @Override
+        public void setBooting(boolean booting) {
+            mBooting = booting;
+        }
+
+        @Override
+        public boolean isBooting() {
+            return mBooting;
+        }
+
+        @Override
+        public void setBooted(boolean booted) {
+            mBooted = booted;
+        }
+
+        @Override
+        public boolean isBooted() {
+            return mBooted;
+        }
+
+        @Override
+        public void finishBooting() {
+            ActivityManagerService.this.finishBooting();
+        }
+
+        @Override
+        public void tempWhitelistForPendingIntent(int callerPid, int callerUid, int targetUid,
+                long duration, String tag) {
+            synchronized (ActivityManagerService.this) {
+                ActivityManagerService.this.tempWhitelistForPendingIntentLocked(
+                        callerPid, callerUid, targetUid, duration, tag);
+            }
+        }
+
+        @Override
+        public int broadcastIntentInPackage(String packageName, int uid, Intent intent,
+                String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData,
+                Bundle resultExtras, String requiredPermission, Bundle bOptions, boolean serialized,
+                boolean sticky, int userId) {
+            synchronized (ActivityManagerService.this) {
+                return ActivityManagerService.this.broadcastIntentInPackage(packageName, uid,
+                        intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
+                        requiredPermission, bOptions, serialized, sticky, userId);
+            }
+        }
+
+        @Override
+        public ComponentName startServiceInPackage(int uid, Intent service, String resolvedType,
+                boolean fgRequired, String callingPackage, int userId)
+                throws TransactionTooLargeException {
+            synchronized(ActivityManagerService.this) {
+                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
+                        "startServiceInPackage: " + service + " type=" + resolvedType);
+                final long origId = Binder.clearCallingIdentity();
+                ComponentName res;
+                try {
+                    res = mServices.startServiceLocked(null, service,
+                            resolvedType, -1, uid, fgRequired, callingPackage, userId);
+                } finally {
+                    Binder.restoreCallingIdentity(origId);
+                }
+                return res;
+            }
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index b24c36a..4bcaf71 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2063,7 +2063,12 @@
             pw.print("has-secure-screen-lock: "); pw.println(kgm.isDeviceSecure());
         }
 
-        ConfigurationInfo configInfo = mInternal.getDeviceConfigurationInfo();
+        ConfigurationInfo configInfo = null;
+        try {
+            configInfo = mTaskInterface.getDeviceConfigurationInfo();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
         if (configInfo.reqGlEsVersion != ConfigurationInfo.GL_ES_VERSION_UNDEFINED) {
             if (protoOutputStream != null) {
                 protoOutputStream.write(DeviceConfigurationProto.OPENGL_VERSION,
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 263c34f..78b42f2 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -3,13 +3,13 @@
 import static android.app.ActivityManager.START_SUCCESS;
 import static android.app.ActivityManager.START_TASK_TO_FRONT;
 import static android.app.ActivityManager.processStateAmToProto;
-import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_TIMEOUT;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_ACTIVITY_START;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_BIND_APPLICATION_DELAY_MS;
@@ -28,9 +28,9 @@
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_IS_NO_DISPLAY;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_IS_VISIBLE;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_IS_VISIBLE_IGNORING_KEYGUARD;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_LAUNCH_MODE;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_MILLIS_SINCE_LAST_LAUNCH;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_MILLIS_SINCE_LAST_VISIBLE;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_LAUNCH_MODE;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_PROCESS_NAME;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_REAL_ACTIVITY;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_ACTIVITY_RECORD_RESULT_TO_PKG_NAME;
@@ -57,16 +57,16 @@
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_PENDING_UI_CLEAN;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_PROCESS_NAME;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_REAL_CALLING_UID;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_REAL_CALLING_UID_PROC_STATE;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_REAL_CALLING_UID_HAS_ANY_VISIBLE_WINDOW;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_REAL_CALLING_UID_PROC_STATE;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TARGET_PACKAGE_NAME;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TARGET_SHORT_COMPONENT_NAME;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TARGET_UID;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TARGET_UID_HAS_ANY_VISIBLE_WINDOW;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TARGET_UID_PROC_STATE;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TARGET_WHITELIST_TAG;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PACKAGE_OPTIMIZATION_COMPILATION_REASON;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PACKAGE_OPTIMIZATION_COMPILATION_FILTER;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PACKAGE_OPTIMIZATION_COMPILATION_REASON;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_COLD_LAUNCH;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_HOT_LAUNCH;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE;
@@ -77,6 +77,7 @@
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.MemoryStatUtil.MemoryStat;
 import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
+import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_TIMEOUT;
 
 import android.content.Context;
 import android.content.Intent;
@@ -98,8 +99,6 @@
 import com.android.internal.os.SomeArgs;
 import com.android.server.LocalServices;
 
-import java.util.ArrayList;
-
 /**
  * Handles logging into Tron.
  */
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 628207c..77cfb12 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -17,18 +17,18 @@
 package com.android.server.am;
 
 import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
-import static android.app.ActivityTaskManager.INVALID_STACK_ID;
 import static android.app.ActivityManager.TaskDescription.ATTR_TASKDESCRIPTION_PREFIX;
 import static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
 import static android.app.ActivityOptions.ANIM_CUSTOM;
+import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS;
 import static android.app.ActivityOptions.ANIM_REMOTE_ANIMATION;
 import static android.app.ActivityOptions.ANIM_SCALE_UP;
 import static android.app.ActivityOptions.ANIM_SCENE_TRANSITION;
-import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS;
 import static android.app.ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_DOWN;
 import static android.app.ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_UP;
 import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
 import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
+import static android.app.ActivityTaskManager.INVALID_STACK_ID;
 import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.OP_PICTURE_IN_PICTURE;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
@@ -81,6 +81,8 @@
 import static android.os.Build.VERSION_CODES.O;
 import static android.os.Process.SYSTEM_UID;
 import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
+
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STATES;
@@ -93,6 +95,13 @@
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityRecordProto.CONFIGURATION_CONTAINER;
+import static com.android.server.am.ActivityRecordProto.FRONT_OF_TASK;
+import static com.android.server.am.ActivityRecordProto.IDENTIFIER;
+import static com.android.server.am.ActivityRecordProto.PROC_ID;
+import static com.android.server.am.ActivityRecordProto.STATE;
+import static com.android.server.am.ActivityRecordProto.TRANSLUCENT;
+import static com.android.server.am.ActivityRecordProto.VISIBLE;
 import static com.android.server.am.ActivityStack.ActivityState.INITIALIZING;
 import static com.android.server.am.ActivityStack.ActivityState.PAUSED;
 import static com.android.server.am.ActivityStack.ActivityState.PAUSING;
@@ -110,14 +119,6 @@
 import static com.android.server.am.TaskPersister.DEBUG;
 import static com.android.server.am.TaskPersister.IMAGE_EXTENSION;
 import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
-import static com.android.server.am.ActivityRecordProto.CONFIGURATION_CONTAINER;
-import static com.android.server.am.ActivityRecordProto.FRONT_OF_TASK;
-import static com.android.server.am.ActivityRecordProto.IDENTIFIER;
-import static com.android.server.am.ActivityRecordProto.PROC_ID;
-import static com.android.server.am.ActivityRecordProto.STATE;
-import static com.android.server.am.ActivityRecordProto.TRANSLUCENT;
-import static com.android.server.am.ActivityRecordProto.VISIBLE;
-import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_LEFT;
 import static com.android.server.wm.IdentifierProto.HASH_CODE;
 import static com.android.server.wm.IdentifierProto.TITLE;
 import static com.android.server.wm.IdentifierProto.USER_ID;
@@ -132,6 +133,7 @@
 import android.app.PendingIntent;
 import android.app.PictureInPictureParams;
 import android.app.ResultInfo;
+import android.app.servertransaction.ActivityConfigurationChangeItem;
 import android.app.servertransaction.ActivityLifecycleItem;
 import android.app.servertransaction.ActivityRelaunchItem;
 import android.app.servertransaction.ClientTransaction;
@@ -143,7 +145,6 @@
 import android.app.servertransaction.PipModeChangeItem;
 import android.app.servertransaction.ResumeActivityItem;
 import android.app.servertransaction.WindowVisibilityItem;
-import android.app.servertransaction.ActivityConfigurationChangeItem;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -1279,20 +1280,14 @@
 
     /**
      * Check whether this activity can be launched on the specified display.
+     *
      * @param displayId Target display id.
-     * @return {@code true} if either it is the default display or this activity is resizeable and
-     *         can be put a secondary screen.
+     * @return {@code true} if either it is the default display or this activity can be put on a
+     *         secondary screen.
      */
     boolean canBeLaunchedOnDisplay(int displayId) {
-        final TaskRecord task = getTask();
-
-        // The resizeability of an Activity's parent task takes precendence over the ActivityInfo.
-        // This allows for a non resizable activity to be launched into a resizeable task.
-        final boolean resizeable =
-                task != null ? task.isResizeable() : supportsResizeableMultiWindow();
-
-        return service.mStackSupervisor.canPlaceEntityOnDisplay(displayId,
-                resizeable, launchedFromPid, launchedFromUid, info);
+        return service.mStackSupervisor.canPlaceEntityOnDisplay(displayId, launchedFromPid,
+                launchedFromUid, info);
     }
 
     /**
@@ -2331,7 +2326,7 @@
         }
 
         final CompatibilityInfo compatInfo =
-                service.mAm.compatibilityInfoForPackageLocked(info.applicationInfo);
+                service.compatibilityInfoForPackageLocked(info.applicationInfo);
         final boolean shown = mWindowContainerController.addStartingWindow(packageName, theme,
                 compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
                 prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(),
@@ -2495,6 +2490,14 @@
         }
     }
 
+    /**
+     * @return {@code true} if this activity was reparented to another display but
+     *         {@link #ensureActivityConfiguration} is not called.
+     */
+    boolean shouldUpdateConfigForDisplayChanged() {
+        return mLastReportedDisplayId != getDisplayId();
+    }
+
     boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow) {
         return ensureActivityConfiguration(globalChanges, preserveWindow,
                 false /* ignoreStopState */);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index aa4e68d..9f59bd8 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -107,6 +107,7 @@
 
 import android.app.Activity;
 import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
 import android.app.IActivityController;
@@ -151,6 +152,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.os.BatteryStatsImpl;
+import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityManagerService.ItemMatcher;
 import com.android.server.wm.ConfigurationContainer;
@@ -1514,14 +1516,14 @@
 
         mStackSupervisor.getLaunchTimeTracker().stopFullyDrawnTraceIfNeeded(getWindowingMode());
 
-        mService.mAm.updateCpuStats();
+        mService.updateCpuStats();
 
         if (prev.attachedToProcess()) {
             if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
             try {
                 EventLogTags.writeAmPauseActivity(prev.userId, System.identityHashCode(prev),
                         prev.shortComponentName, "userLeaving=" + userLeaving);
-                mService.mAm.updateUsageStats(prev, false);
+                mService.updateUsageStats(prev, false);
 
                 mService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),
                         prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving,
@@ -1683,20 +1685,13 @@
         if (prev != null) {
             prev.resumeKeyDispatchingLocked();
 
-            if (prev.hasProcess() && prev.cpuTimeAtResume > 0
-                    && mService.mAm.mBatteryStatsService.isOnBattery()) {
-                long diff = prev.app.getCpuTime() - prev.cpuTimeAtResume;
-                if (diff > 0) {
-                    BatteryStatsImpl bsi = mService.mAm.mBatteryStatsService.getActiveStatistics();
-                    synchronized (bsi) {
-                        BatteryStatsImpl.Uid.Proc ps =
-                                bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
-                                        prev.info.packageName);
-                        if (ps != null) {
-                            ps.addForegroundTimeLocked(diff);
-                        }
-                    }
-                }
+            final long diff = prev.app.getCpuTime() - prev.cpuTimeAtResume;
+            if (prev.hasProcess() && prev.cpuTimeAtResume > 0 && diff > 0) {
+                final Runnable r = PooledLambda.obtainRunnable(
+                        ActivityManagerInternal::updateForegroundTimeIfOnBattery,
+                        mService.mAmInternal, prev.info.packageName, prev.info.applicationInfo.uid,
+                        diff);
+                mService.mH.post(r);
             }
             prev.cpuTimeAtResume = 0; // reset it
         }
@@ -1713,7 +1708,7 @@
         mStackSupervisor.ensureActivitiesVisibleLocked(resuming, 0, !PRESERVE_WINDOWS);
     }
 
-    void addToStopping(ActivityRecord r, boolean scheduleIdle, boolean idleDelayed) {
+    private void addToStopping(ActivityRecord r, boolean scheduleIdle, boolean idleDelayed) {
         if (!mStackSupervisor.mStoppingActivities.contains(r)) {
             mStackSupervisor.mStoppingActivities.add(r);
 
@@ -2407,7 +2402,7 @@
 
     @GuardedBy("mService")
     private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
-        if (!mService.mAm.mBooting && !mService.mAm.mBooted) {
+        if (!mService.isBooting() && !mService.isBooted()) {
             // Not ready yet!
             return false;
         }
@@ -2455,13 +2450,24 @@
         if (shouldSleepOrShutDownActivities()
                 && mLastPausedActivity == next
                 && mStackSupervisor.allPausedActivitiesComplete()) {
-            // Make sure we have executed any pending transitions, since there
-            // should be nothing left to do at this point.
-            executeAppTransition(options);
-            if (DEBUG_STATES) Slog.d(TAG_STATES,
-                    "resumeTopActivityLocked: Going to sleep and all paused");
-            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
-            return false;
+            // If the current top activity may be able to occlude keyguard but the occluded state
+            // has not been set, update visibility and check again if we should continue to resume.
+            boolean nothingToResume = true;
+            if (!mService.mShuttingDown && !mTopActivityOccludesKeyguard
+                    && next.canShowWhenLocked()) {
+                ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */,
+                        !PRESERVE_WINDOWS);
+                nothingToResume = shouldSleepActivities();
+            }
+            if (nothingToResume) {
+                // Make sure we have executed any pending transitions, since there
+                // should be nothing left to do at this point.
+                executeAppTransition(options);
+                if (DEBUG_STATES) Slog.d(TAG_STATES,
+                        "resumeTopActivityLocked: Going to sleep and all paused");
+                if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
+                return false;
+            }
         }
 
         // Make sure that the user who owns this activity is started.  If not,
@@ -2691,7 +2697,7 @@
                         lastStack == null ? null :lastStack.mResumedActivity;
                 final ActivityState lastState = next.getState();
 
-                mService.mAm.updateCpuStats();
+                mService.updateCpuStats();
 
                 if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + next
                         + " (in existing)");
@@ -4149,7 +4155,7 @@
             for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
                 PendingIntentRecord rec = apr.get();
                 if (rec != null) {
-                    mService.mAm.cancelIntentSenderLocked(rec, false);
+                    mService.mPendingIntentController.cancelIntentSender(rec, false);
                 }
             }
             r.pendingResults = null;
@@ -4166,7 +4172,7 @@
         mWindowManager.notifyAppRelaunchesCleared(r.appToken);
     }
 
-    void removeTimeoutsForActivityLocked(ActivityRecord r) {
+    private void removeTimeoutsForActivityLocked(ActivityRecord r) {
         mStackSupervisor.removeTimeoutsForActivityLocked(r);
         mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
         mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
@@ -4368,12 +4374,8 @@
         if (hadApp) {
             if (removeFromApp) {
                 r.app.removeActivity(r);
-                if (mService.mAm.mHeavyWeightProcess != null
-                        && mService.mAm.mHeavyWeightProcess.getWindowProcessController() == r.app
-                        && !r.app.hasActivities()) {
-                    mService.mAm.mHeavyWeightProcess = null;
-                    mService.mAm.mHandler.sendEmptyMessage(
-                            ActivityManagerService.CANCEL_HEAVY_NOTIFICATION_MSG);
+                if (!r.app.hasActivities()) {
+                    mService.clearHeavyWeightProcessIfEquals(r.app);
                 }
                 if (!r.app.hasActivities()) {
                     // Update any services we are bound to that might care about whether
@@ -4564,7 +4566,7 @@
                                     r.getTask().taskId, r.shortComponentName,
                                     "proc died without state saved");
                             if (r.getState() == RESUMED) {
-                                mService.mAm.updateUsageStats(r, false);
+                                mService.updateUsageStats(r, false);
                             }
                         }
                     } else {
@@ -5375,12 +5377,14 @@
         display.positionChildAtTop(this, false /* includingParents */);
     }
 
+    /** NOTE: Should only be called from {@link TaskRecord#reparent}. */
     void moveToFrontAndResumeStateIfNeeded(ActivityRecord r, boolean moveToFront, boolean setResume,
             boolean setPause, String reason) {
         if (!moveToFront) {
             return;
         }
 
+        final ActivityState origState = r.getState();
         // If the activity owns the last resumed activity, transfer that together,
         // so that we don't resume the same activity again in the new stack.
         // Apps may depend on onResume()/onPause() being called in pairs.
@@ -5393,9 +5397,14 @@
             mPausingActivity = r;
             schedulePauseTimeout(r);
         }
-        // Move the stack in which we are placing the activity to the front. The call will also
-        // make sure the activity focus is set.
+        // Move the stack in which we are placing the activity to the front.
         moveToFront(reason);
+        // If the original state is resumed, there is no state change to update focused app.
+        // So here makes sure the activity focus is set if it is the top.
+        if (origState == RESUMED && r == mStackSupervisor.getTopResumedActivity()) {
+            // TODO(b/111361570): Support multiple focused apps in WM
+            mService.setResumedActivityUncheckLocked(r, reason);
+        }
     }
 
     public int getStackId() {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 310898e..877c856 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -488,8 +488,8 @@
     }
 
     /** Check if placing task or activity on specified display is allowed. */
-    boolean canPlaceEntityOnDisplay(int displayId, boolean resizeable, int callingPid,
-            int callingUid, ActivityInfo activityInfo) {
+    boolean canPlaceEntityOnDisplay(int displayId, int callingPid, int callingUid,
+            ActivityInfo activityInfo) {
         if (displayId == DEFAULT_DISPLAY) {
             // No restrictions for the default display.
             return true;
@@ -498,10 +498,6 @@
             // Can't launch on secondary displays if feature is not supported.
             return false;
         }
-        if (!resizeable && !displayConfigMatchesGlobal(displayId)) {
-            // Can't apply wrong configuration to non-resizeable activities.
-            return false;
-        }
         if (!isCallerAllowedToLaunchOnDisplay(callingPid, callingUid, displayId, activityInfo)) {
             // Can't place activities to a display that has restricted launch rules.
             // In this case the request should be made by explicitly adding target display id and
@@ -690,7 +686,7 @@
         mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
 
         final Display[] displays = mDisplayManager.getDisplays();
-        for (int displayNdx = displays.length - 1; displayNdx >= 0; --displayNdx) {
+        for (int displayNdx = 0; displayNdx < displays.length; ++displayNdx) {
             final Display display = displays[displayNdx];
             final ActivityDisplay activityDisplay = new ActivityDisplay(this, display);
             if (activityDisplay.mDisplayId == DEFAULT_DISPLAY) {
@@ -804,7 +800,7 @@
         }
 
         final ActivityRecord r = topRunningActivityLocked();
-        if (mService.mAm.mBooting || !mService.mAm.mBooted) {
+        if (mService.isBooting() || !mService.isBooted()) {
             if (r != null && r.idle) {
                 checkFinishBootingLocked();
             }
@@ -836,7 +832,7 @@
     }
 
     boolean resumeHomeStackTask(ActivityRecord prev, String reason) {
-        if (!mService.mAm.mBooting && !mService.mAm.mBooted) {
+        if (!mService.isBooting() && !mService.isBooted()) {
             // Not ready yet!
             return false;
         }
@@ -1534,7 +1530,7 @@
                 r.sleeping = false;
                 r.forceNewConfig = false;
                 mService.getAppWarningsLocked().onStartActivity(r);
-                r.compat = mService.mAm.compatibilityInfoForPackageLocked(r.info.applicationInfo);
+                r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo);
                 ProfilerInfo profilerInfo = null;
                 if (mService.mAm.mProfileApp != null && mService.mAm.mProfileApp.equals(app.processName)) {
                     if (mService.mAm.mProfileProc == null || mService.mAm.mProfileProc == app) {
@@ -1562,7 +1558,8 @@
                 // we have to always create a new Configuration here.
 
                 final MergedConfiguration mergedConfiguration = new MergedConfiguration(
-                        mService.getGlobalConfiguration(), r.getMergedOverrideConfiguration());
+                        app.getWindowProcessController().getConfiguration(),
+                        r.getMergedOverrideConfiguration());
                 r.setLastReportedConfiguration(mergedConfiguration);
 
                 logIfTransactionTooLarge(r.intent, r.icicle);
@@ -1595,22 +1592,17 @@
 
                 if ((app.info.privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0
                         && mService.mAm.mHasHeavyWeightFeature) {
-                    // This may be a heavy-weight process!  Note that the package
-                    // manager will ensure that only activity can run in the main
-                    // process of the .apk, which is the only thing that will be
-                    // considered heavy-weight.
+                    // This may be a heavy-weight process! Note that the package manager will ensure
+                    // that only activity can run in the main process of the .apk, which is the only
+                    // thing that will be considered heavy-weight.
                     if (app.processName.equals(app.info.packageName)) {
-                        if (mService.mAm.mHeavyWeightProcess != null
-                                && mService.mAm.mHeavyWeightProcess != app) {
-                            Slog.w(TAG, "Starting new heavy weight process " + app
+                        if (mService.mHeavyWeightProcess != null
+                                && mService.mHeavyWeightProcess != proc) {
+                            Slog.w(TAG, "Starting new heavy weight process " + proc
                                     + " when already running "
-                                    + mService.mAm.mHeavyWeightProcess);
+                                    + mService.mHeavyWeightProcess);
                         }
-                        mService.mAm.mHeavyWeightProcess = app;
-                        Message msg = mService.mAm.mHandler.obtainMessage(
-                                ActivityManagerService.POST_HEAVY_NOTIFICATION_MSG);
-                        msg.obj = r;
-                        mService.mAm.mHandler.sendMessage(msg);
+                        mService.setHeavyWeightProcess(r);
                     }
                 }
 
@@ -2057,15 +2049,15 @@
      */
     @GuardedBy("mService")
     private boolean checkFinishBootingLocked() {
-        final boolean booting = mService.mAm.mBooting;
+        final boolean booting = mService.isBooting();
         boolean enableScreen = false;
-        mService.mAm.mBooting = false;
-        if (!mService.mAm.mBooted) {
-            mService.mAm.mBooted = true;
+        mService.setBooting(false);
+        if (!mService.isBooted()) {
+            mService.setBooted(true);
             enableScreen = true;
         }
         if (booting || enableScreen) {
-            mService.mAm.postFinishBooting(booting, enableScreen);
+            mService.postFinishBooting(booting, enableScreen);
         }
         return booting;
     }
@@ -3196,10 +3188,10 @@
 
         // Kill the running processes. Post on handle since we don't want to hold the service lock
         // while calling into AM.
-        final Runnable r = PooledLambda.obtainRunnable(
+        final Message m = PooledLambda.obtainMessage(
                 ActivityManagerInternal::killProcessesForRemovedTask, mService.mAmInternal,
                 procsToKill);
-        mService.mH.post(r);
+        mService.mH.sendMessage(m);
     }
 
     /**
@@ -3686,7 +3678,7 @@
 
         final ActivityStack stack = r.getStack();
         if (isTopDisplayFocusedStack(stack)) {
-            mService.mAm.updateUsageStats(r, true);
+            mService.updateUsageStats(r, true);
         }
         if (allResumedActivitiesComplete()) {
             ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
@@ -4530,11 +4522,14 @@
             mService.setTaskWindowingMode(task.taskId,
                     WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY, true /* toTop */);
             if (preferredDisplayId != actualDisplayId) {
-                // Display a warning toast that we tried to put a non-resizeable task on a secondary
-                // display with config different from global config.
+                Slog.w(TAG, "Failed to put " + task + " on display " + preferredDisplayId);
+                // Display a warning toast that we failed to put a task on a secondary display.
                 mService.getTaskChangeNotificationController()
                         .notifyActivityLaunchOnSecondaryDisplayFailed();
                 return;
+            } else if (!forceNonResizable && handleForcedResizableTask(task,
+                    FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY)) {
+                return;
             }
         }
 
@@ -4554,16 +4549,23 @@
             return;
         }
 
+        handleForcedResizableTask(task, FORCED_RESIZEABLE_REASON_SPLIT_SCREEN);
+    }
+
+    /**
+     * @return {@code true} if the top activity of the task is forced to be resizable and the user
+     *         was notified about activity being forced resized.
+     */
+    private boolean handleForcedResizableTask(TaskRecord task, int reason) {
         final ActivityRecord topActivity = task.getTopActivity();
         if (topActivity != null && topActivity.isNonResizableOrForcedResizable()
-            && !topActivity.noDisplay) {
+                && !topActivity.noDisplay) {
             final String packageName = topActivity.appInfo.packageName;
-            final int reason = isSecondaryDisplayPreferred
-                    ? FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY
-                    : FORCED_RESIZEABLE_REASON_SPLIT_SCREEN;
             mService.getTaskChangeNotificationController().notifyActivityForcedResizable(
                     task.taskId, reason, packageName);
+            return true;
         }
+        return false;
     }
 
     void activityRelaunchedLocked(IBinder token) {
diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
index 177e2f5..1fb8f87 100644
--- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
@@ -126,7 +126,7 @@
 
     private IntentSender createIntentSenderForOriginalIntent(int callingUid, int flags) {
         Bundle activityOptions = deferCrossProfileAppsAnimationIfNecessary();
-        final IIntentSender target = mService.mAm.getIntentSenderLocked(
+        final IIntentSender target = mService.getIntentSenderLocked(
                 INTENT_SENDER_ACTIVITY, mCallingPackage, callingUid, mUserId, null /*token*/,
                 null /*resultCode*/, 0 /*requestCode*/,
                 new Intent[] { mIntent }, new String[] { mResolvedType },
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index eb41fe7..890aafe 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -52,6 +52,7 @@
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
+
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
@@ -782,7 +783,7 @@
         if (aInfo != null) {
             if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
                     aInfo.packageName, userId)) {
-                IIntentSender target = mService.mAm.getIntentSenderLocked(
+                IIntentSender target = mService.getIntentSenderLocked(
                         ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
                         callingUid, userId, null, null, 0, new Intent[]{intent},
                         new String[]{resolvedType}, PendingIntent.FLAG_CANCEL_CURRENT
@@ -944,7 +945,8 @@
                 auxiliaryResponse == null ? null : auxiliaryResponse.filters);
     }
 
-    void postStartActivityProcessing(ActivityRecord r, int result, ActivityStack targetStack) {
+    void postStartActivityProcessing(ActivityRecord r, int result,
+            ActivityStack startedActivityStack) {
         if (ActivityManager.isStartResultFatalError(result)) {
             return;
         }
@@ -956,14 +958,6 @@
         // about this, so it waits for the new activity to become visible instead.
         mSupervisor.reportWaitingActivityLaunchedIfNeeded(r, result);
 
-        ActivityStack startedActivityStack = null;
-        final ActivityStack currentStack = r.getStack();
-        if (currentStack != null) {
-            startedActivityStack = currentStack;
-        } else if (mTargetStack != null) {
-            startedActivityStack = targetStack;
-        }
-
         if (startedActivityStack == null) {
             return;
         }
@@ -1085,9 +1079,9 @@
                 // This may be a heavy-weight process!  Check to see if we already
                 // have another, different heavy-weight process running.
                 if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
-                    final ProcessRecord heavy = mService.mAm.mHeavyWeightProcess;
-                    if (heavy != null && (heavy.info.uid != aInfo.applicationInfo.uid
-                            || !heavy.processName.equals(aInfo.processName))) {
+                    final WindowProcessController heavy = mService.mHeavyWeightProcess;
+                    if (heavy != null && (heavy.mInfo.uid != aInfo.applicationInfo.uid
+                            || !heavy.mName.equals(aInfo.processName))) {
                         int appCallingUid = callingUid;
                         if (caller != null) {
                             ProcessRecord callerApp = mService.mAm.getRecordForAppLocked(caller);
@@ -1102,7 +1096,7 @@
                             }
                         }
 
-                        IIntentSender target = mService.mAm.getIntentSenderLocked(
+                        IIntentSender target = mService.getIntentSenderLocked(
                                 ActivityManager.INTENT_SENDER_ACTIVITY, "android",
                                 appCallingUid, userId, null, null, 0, new Intent[] { intent },
                                 new String[] { resolvedType }, PendingIntent.FLAG_CANCEL_CURRENT
@@ -1115,8 +1109,7 @@
                         }
                         newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT,
                                 new IntentSender(target));
-                        heavy.getWindowProcessController().updateIntentForHeavyWeightActivity(
-                                newIntent);
+                        heavy.updateIntentForHeavyWeightActivity(newIntent);
                         newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,
                                 aInfo.packageName);
                         newIntent.setFlags(intent.getFlags());
@@ -1239,23 +1232,41 @@
                 int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
                 ActivityRecord[] outActivity) {
         int result = START_CANCELED;
+        final ActivityStack startedActivityStack;
         try {
             mService.mWindowManager.deferSurfaceLayout();
             result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
                     startFlags, doResume, options, inTask, outActivity);
         } finally {
-            // If we are not able to proceed, disassociate the activity from the task. Leaving an
-            // activity in an incomplete state can lead to issues, such as performing operations
-            // without a window container.
-            final ActivityStack stack = mStartActivity.getStack();
-            if (!ActivityManager.isStartResultSuccessful(result) && stack != null) {
-                stack.finishActivityLocked(mStartActivity, RESULT_CANCELED,
-                        null /* intentResultData */, "startActivity", true /* oomAdj */);
+            final ActivityStack currentStack = r.getStack();
+            startedActivityStack = currentStack != null ? currentStack : mTargetStack;
+
+            if (ActivityManager.isStartResultSuccessful(result)) {
+                if (startedActivityStack != null) {
+                    // If there is no state change (e.g. a resumed activity is reparented to
+                    // top of another display) to trigger a visibility/configuration checking,
+                    // we have to update the configuration for changing to different display.
+                    final ActivityRecord currentTop =
+                            startedActivityStack.topRunningActivityLocked();
+                    if (currentTop != null && currentTop.shouldUpdateConfigForDisplayChanged()) {
+                        mSupervisor.ensureVisibilityAndConfig(currentTop, currentTop.getDisplayId(),
+                                true /* markFrozenIfConfigChanged */, false /* deferResume */);
+                    }
+                }
+            } else {
+                // If we are not able to proceed, disassociate the activity from the task.
+                // Leaving an activity in an incomplete state can lead to issues, such as
+                // performing operations without a window container.
+                final ActivityStack stack = mStartActivity.getStack();
+                if (stack != null) {
+                    stack.finishActivityLocked(mStartActivity, RESULT_CANCELED,
+                            null /* intentResultData */, "startActivity", true /* oomAdj */);
+                }
             }
             mService.mWindowManager.continueSurfaceLayout();
         }
 
-        postStartActivityProcessing(r, result, mTargetStack);
+        postStartActivityProcessing(r, result, startedActivityStack);
 
         return result;
     }
@@ -1901,14 +1912,20 @@
         // except...  well, with SINGLE_TASK_LAUNCH it's not entirely clear. We'd like to have
         // the same behavior as if a new instance was being started, which means not bringing it
         // to the front if the caller is not itself in the front.
-        final ActivityStack focusStack = mSupervisor.getTopDisplayFocusedStack();
-        ActivityRecord curTop = (focusStack == null)
-                ? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);
+        final boolean differentTopTask;
+        if (mPreferredDisplayId == mTargetStack.mDisplayId) {
+            final ActivityStack focusStack = mTargetStack.getDisplay().getFocusedStack();
+            final ActivityRecord curTop = (focusStack == null)
+                    ? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);
+            final TaskRecord topTask = curTop != null ? curTop.getTask() : null;
+            differentTopTask = topTask != null
+                    && (topTask != intentActivity.getTask() || topTask != focusStack.topTask());
+        } else {
+            // The existing task should always be different from those in other displays.
+            differentTopTask = true;
+        }
 
-        final TaskRecord topTask = curTop != null ? curTop.getTask() : null;
-        if (topTask != null
-                && (topTask != intentActivity.getTask() || topTask != focusStack.topTask())
-                && !mAvoidMoveToFront) {
+        if (differentTopTask && !mAvoidMoveToFront) {
             mStartActivity.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
             if (mSourceRecord == null || (mSourceStack.getTopActivity() != null &&
                     mSourceStack.getTopActivity().getTask() == mSourceRecord.getTask())) {
diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
index 212844a..add9f2a 100644
--- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
@@ -125,7 +125,11 @@
 import android.app.IActivityTaskManager;
 import android.app.IApplicationThread;
 import android.app.IAssistDataReceiver;
+import android.app.INotificationManager;
 import android.app.ITaskStackListener;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
 import android.app.PictureInPictureParams;
 import android.app.ProfilerInfo;
 import android.app.RemoteAction;
@@ -145,11 +149,13 @@
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.ConfigurationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
+import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.database.ContentObserver;
@@ -208,10 +214,13 @@
 import com.android.internal.app.ProcessMap;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.os.logging.MetricsLoggerWrapper;
 import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.KeyguardDismissCallback;
 import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.AppOpsService;
 import com.android.server.AttributeCache;
 import com.android.server.LocalServices;
@@ -230,7 +239,9 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 
@@ -266,6 +277,8 @@
     ActivityManagerInternal mAmInternal;
     UriGrantsManagerInternal mUgmInternal;
     private PackageManagerInternal mPmInternal;
+    private ActivityTaskManagerInternal mInternal;
+    PendingIntentController mPendingIntentController;
     /* Global service lock used by the package the owns this service. */
     Object mGlobalLock;
     ActivityStackSupervisor mStackSupervisor;
@@ -278,6 +291,8 @@
     final SparseArray<WindowProcessController> mPidMap = new SparseArray<>();
     /** This is the process holding what we currently consider to be the "home" activity. */
     WindowProcessController mHomeProcess;
+    /** The currently running heavy-weight process, if any. */
+    WindowProcessController mHeavyWeightProcess = null;
     /**
      * This is the process holding the activity the user last visited that is in a different process
      * from the one they are currently in.
@@ -475,6 +490,12 @@
 
     private AppWarnings mAppWarnings;
 
+    /**
+     * Packages that the user has asked to have run in screen size
+     * compatibility mode instead of filling the screen.
+     */
+    CompatModePackages mCompatModePackages;
+
     private FontScaleSettingObserver mFontScaleSettingObserver;
 
     private final class FontScaleSettingObserver extends ContentObserver {
@@ -607,8 +628,10 @@
         mGlobalLock = mAm;
         mH = new H(mAm.mHandlerThread.getLooper());
         mUiHandler = new UiHandler();
-        mAppWarnings = new AppWarnings(
-                this, mUiContext, mH, mUiHandler, SystemServiceManager.ensureSystemDir());
+        final File systemDir = SystemServiceManager.ensureSystemDir();
+        mAppWarnings = new AppWarnings(this, mUiContext, mH, mUiHandler, systemDir);
+        mCompatModePackages = new CompatModePackages(this, systemDir, mH);
+        mPendingIntentController = mAm.mPendingIntentController;
 
         mTempConfig.setToDefaults();
         mTempConfig.setLocales(LocaleList.getDefault());
@@ -631,6 +654,11 @@
         mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
     }
 
+    int increaseConfigurationSeqLocked() {
+        mConfigurationSeq = Math.max(++mConfigurationSeq, 1);
+        return mConfigurationSeq;
+    }
+
     protected ActivityStackSupervisor createStackSupervisor() {
         final ActivityStackSupervisor supervisor = new ActivityStackSupervisor(this, mH.getLooper());
         supervisor.initialize();
@@ -686,8 +714,49 @@
         return mLockTaskController;
     }
 
+    /**
+     * Return the global configuration used by the process corresponding to the input pid. This is
+     * usually the global configuration with some overrides specific to that process.
+     */
+    Configuration getGlobalConfigurationForCallingPid() {
+        final int pid = Binder.getCallingPid();
+        if (pid == MY_PID || pid < 0) {
+            return getGlobalConfiguration();
+        }
+        synchronized (mGlobalLock) {
+            final WindowProcessController app = mPidMap.get(pid);
+            return app != null ? app.getConfiguration() : getGlobalConfiguration();
+        }
+    }
+
+    /**
+     * Return the device configuration info used by the process corresponding to the input pid.
+     * The value is consistent with the global configuration for the process.
+     */
+    @Override
+    public ConfigurationInfo getDeviceConfigurationInfo() {
+        ConfigurationInfo config = new ConfigurationInfo();
+        synchronized (mGlobalLock) {
+            final Configuration globalConfig = getGlobalConfigurationForCallingPid();
+            config.reqTouchScreen = globalConfig.touchscreen;
+            config.reqKeyboardType = globalConfig.keyboard;
+            config.reqNavigation = globalConfig.navigation;
+            if (globalConfig.navigation == Configuration.NAVIGATION_DPAD
+                    || globalConfig.navigation == Configuration.NAVIGATION_TRACKBALL) {
+                config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
+            }
+            if (globalConfig.keyboard != Configuration.KEYBOARD_UNDEFINED
+                    && globalConfig.keyboard != Configuration.KEYBOARD_NOKEYS) {
+                config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
+            }
+            config.reqGlEsVersion = mAm.GL_ES_VERSION;
+        }
+        return config;
+    }
+
     private void start() {
-        LocalServices.addService(ActivityTaskManagerInternal.class, new LocalService());
+        mInternal = new LocalService();
+        LocalServices.addService(ActivityTaskManagerInternal.class, mInternal);
     }
 
     public static final class Lifecycle extends SystemService {
@@ -1461,16 +1530,13 @@
     @Override
     public int getFrontActivityScreenCompatMode() {
         enforceNotIsolatedCaller("getFrontActivityScreenCompatMode");
-        ApplicationInfo ai;
         synchronized (mGlobalLock) {
             final ActivityRecord r = getTopDisplayFocusedStack().topRunningActivityLocked();
             if (r == null) {
                 return ActivityManager.COMPAT_MODE_UNKNOWN;
             }
-            ai = r.info.applicationInfo;
+            return mCompatModePackages.computeCompatModeLocked(r.info.applicationInfo);
         }
-
-        return mAmInternal.getPackageScreenCompatMode(ai);
     }
 
     @Override
@@ -1485,9 +1551,8 @@
                 return;
             }
             ai = r.info.applicationInfo;
+            mCompatModePackages.setPackageScreenCompatModeLocked(ai, mode);
         }
-
-        mAmInternal.setPackageScreenCompatMode(ai, mode);
     }
 
     @Override
@@ -4112,7 +4177,7 @@
         return mVrController.shouldDisableNonVrUiLocked();
     }
 
-    void applyUpdateVrModeLocked(ActivityRecord r) {
+    private void applyUpdateVrModeLocked(ActivityRecord r) {
         // VR apps are expected to run in a main display. If an app is turning on VR for
         // itself, but lives in a dynamic stack, then make sure that it is moved to the main
         // fullscreen stack before enabling VR Mode.
@@ -4143,6 +4208,40 @@
         });
     }
 
+    @Override
+    public int getPackageScreenCompatMode(String packageName) {
+        enforceNotIsolatedCaller("getPackageScreenCompatMode");
+        synchronized (mGlobalLock) {
+            return mCompatModePackages.getPackageScreenCompatModeLocked(packageName);
+        }
+    }
+
+    @Override
+    public void setPackageScreenCompatMode(String packageName, int mode) {
+        mAmInternal.enforceCallingPermission(android.Manifest.permission.SET_SCREEN_COMPATIBILITY,
+                "setPackageScreenCompatMode");
+        synchronized (mGlobalLock) {
+            mCompatModePackages.setPackageScreenCompatModeLocked(packageName, mode);
+        }
+    }
+
+    @Override
+    public boolean getPackageAskScreenCompat(String packageName) {
+        enforceNotIsolatedCaller("getPackageAskScreenCompat");
+        synchronized (mGlobalLock) {
+            return mCompatModePackages.getPackageAskCompatModeLocked(packageName);
+        }
+    }
+
+    @Override
+    public void setPackageAskScreenCompat(String packageName, boolean ask) {
+        mAmInternal.enforceCallingPermission(android.Manifest.permission.SET_SCREEN_COMPATIBILITY,
+                "setPackageAskScreenCompat");
+        synchronized (mGlobalLock) {
+            mCompatModePackages.setPackageAskCompatModeLocked(packageName, ask);
+        }
+    }
+
     ActivityStack getTopDisplayFocusedStack() {
         return mStackSupervisor.getTopDisplayFocusedStack();
     }
@@ -4215,7 +4314,7 @@
     public Configuration getConfiguration() {
         Configuration ci;
         synchronized(mGlobalLock) {
-            ci = new Configuration(getGlobalConfiguration());
+            ci = new Configuration(getGlobalConfigurationForCallingPid());
             ci.userSetLocale = false;
         }
         return ci;
@@ -4371,8 +4470,7 @@
                     locales.get(bestLocaleIndex)));
         }
 
-        mConfigurationSeq = Math.max(++mConfigurationSeq, 1);
-        mTempConfig.seq = mConfigurationSeq;
+        mTempConfig.seq = increaseConfigurationSeqLocked();
 
         // Update stored global config and notify everyone about the change.
         mStackSupervisor.onConfigurationChanged(mTempConfig);
@@ -4406,6 +4504,7 @@
             mAm.mHandler.sendMessage(msg);
         }
 
+        // TODO: Consider using mPidMap to update configurations for processes.
         for (int i = mAm.mLruProcesses.size() - 1; i >= 0; i--) {
             ProcessRecord app = mAm.mLruProcesses.get(i);
             try {
@@ -4688,11 +4787,7 @@
         return mSleeping;
     }
 
-    /**
-     * Update AMS states when an activity is resumed. This should only be called by
-     * {@link ActivityStack#onActivityStateChanged(
-     * ActivityRecord, ActivityStack.ActivityState, String)} when an activity is resumed.
-     */
+    /** Update AMS states when an activity is resumed. */
     void setResumedActivityUncheckLocked(ActivityRecord r, String reason) {
         final TaskRecord task = r.getTask();
         if (task.isActivityTypeStandard()) {
@@ -4812,6 +4907,155 @@
         mH.post(mAmInternal::updateOomAdj);
     }
 
+    void updateCpuStats() {
+        mH.post(mAmInternal::updateCpuStats);
+    }
+
+    void updateUsageStats(ActivityRecord component, boolean resumed) {
+        final Message m = PooledLambda.obtainMessage(ActivityManagerInternal::updateUsageStats,
+                mAmInternal, component.realActivity, component.app.mUid, component.userId, resumed);
+        mH.sendMessage(m);
+    }
+
+    void setBooting(boolean booting) {
+        mAmInternal.setBooting(booting);
+    }
+
+    boolean isBooting() {
+        return mAmInternal.isBooting();
+    }
+
+    void setBooted(boolean booted) {
+        mAmInternal.setBooted(booted);
+    }
+
+    boolean isBooted() {
+        return mAmInternal.isBooted();
+    }
+
+    void postFinishBooting(boolean finishBooting, boolean enableScreen) {
+        mH.post(() -> {
+            if (finishBooting) {
+                mAmInternal.finishBooting();
+            }
+            if (enableScreen) {
+                mInternal.enableScreenAfterBoot(isBooted());
+            }
+        });
+    }
+
+    void setHeavyWeightProcess(ActivityRecord root) {
+        mHeavyWeightProcess = root.app;
+        final Message m = PooledLambda.obtainMessage(
+                ActivityTaskManagerService::postHeavyWeightProcessNotification, this,
+                root.app, root.intent, root.userId);
+        mH.sendMessage(m);
+    }
+
+    void clearHeavyWeightProcessIfEquals(WindowProcessController proc) {
+        if (mHeavyWeightProcess == null || mHeavyWeightProcess != proc) {
+            return;
+        }
+
+        mHeavyWeightProcess = null;
+        final Message m = PooledLambda.obtainMessage(
+                ActivityTaskManagerService::cancelHeavyWeightProcessNotification, this,
+                proc.mUserId);
+        mH.sendMessage(m);
+    }
+
+    private void cancelHeavyWeightProcessNotification(int userId) {
+        final INotificationManager inm = NotificationManager.getService();
+        if (inm == null) {
+            return;
+        }
+        try {
+            inm.cancelNotificationWithTag("android", null,
+                    SystemMessage.NOTE_HEAVY_WEIGHT_NOTIFICATION, userId);
+        } catch (RuntimeException e) {
+            Slog.w(TAG, "Error canceling notification for service", e);
+        } catch (RemoteException e) {
+        }
+
+    }
+
+    private void postHeavyWeightProcessNotification(
+            WindowProcessController proc, Intent intent, int userId) {
+        if (proc == null) {
+            return;
+        }
+
+        final INotificationManager inm = NotificationManager.getService();
+        if (inm == null) {
+            return;
+        }
+
+        try {
+            Context context = mContext.createPackageContext(proc.mInfo.packageName, 0);
+            String text = mContext.getString(R.string.heavy_weight_notification,
+                    context.getApplicationInfo().loadLabel(context.getPackageManager()));
+            Notification notification =
+                    new Notification.Builder(context,
+                            SystemNotificationChannels.HEAVY_WEIGHT_APP)
+                            .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+                            .setWhen(0)
+                            .setOngoing(true)
+                            .setTicker(text)
+                            .setColor(mContext.getColor(
+                                    com.android.internal.R.color.system_notification_accent_color))
+                            .setContentTitle(text)
+                            .setContentText(
+                                    mContext.getText(R.string.heavy_weight_notification_detail))
+                            .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0,
+                                    intent, PendingIntent.FLAG_CANCEL_CURRENT, null,
+                                    new UserHandle(userId)))
+                            .build();
+            try {
+                inm.enqueueNotificationWithTag("android", "android", null,
+                        SystemMessage.NOTE_HEAVY_WEIGHT_NOTIFICATION, notification, userId);
+            } catch (RuntimeException e) {
+                Slog.w(TAG, "Error showing notification for heavy-weight app", e);
+            } catch (RemoteException e) {
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            Slog.w(TAG, "Unable to create context for heavy notification", e);
+        }
+
+    }
+
+    IIntentSender getIntentSenderLocked(int type, String packageName, int callingUid, int userId,
+            IBinder token, String resultWho, int requestCode, Intent[] intents,
+            String[] resolvedTypes, int flags, Bundle bOptions) {
+
+        ActivityRecord activity = null;
+        if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) {
+            activity = ActivityRecord.isInStackLocked(token);
+            if (activity == null) {
+                Slog.w(TAG, "Failed createPendingResult: activity " + token + " not in any stack");
+                return null;
+            }
+            if (activity.finishing) {
+                Slog.w(TAG, "Failed createPendingResult: activity " + activity + " is finishing");
+                return null;
+            }
+        }
+
+        final PendingIntentRecord rec = mPendingIntentController.getIntentSender(type, packageName,
+                callingUid, userId, token, resultWho, requestCode, intents, resolvedTypes, flags,
+                bOptions);
+        final boolean noCreate = (flags & PendingIntent.FLAG_NO_CREATE) != 0;
+        if (noCreate) {
+            return rec;
+        }
+        if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) {
+            if (activity.pendingResults == null) {
+                activity.pendingResults = new HashSet<>();
+            }
+            activity.pendingResults.add(rec.ref);
+        }
+        return rec;
+    }
+
     // TODO(b/111541062): Update app time tracking to make it aware of multiple resumed activities
     private void startTimeTrackingFocusedActivityLocked() {
         final ActivityRecord resumedActivity = mStackSupervisor.getTopResumedActivity();
@@ -4888,6 +5132,10 @@
         mH.post(() -> mAmInternal.scheduleAppGcs());
     }
 
+    CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) {
+        return mCompatModePackages.compatibilityInfoForPackageLocked(ai);
+    }
+
     /**
      * Returns the PackageManager. Used by classes hosted by {@link ActivityTaskManagerService}. The
      * PackageManager could be unavailable at construction time and therefore needs to be accessed
@@ -5099,6 +5347,31 @@
         }
 
         @Override
+        public int startActivitiesInPackage(int uid, String callingPackage, Intent[] intents,
+                String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId,
+                boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent) {
+            synchronized (mGlobalLock) {
+                return getActivityStartController().startActivitiesInPackage(uid, callingPackage,
+                        intents, resolvedTypes, resultTo, options, userId, validateIncomingUser,
+                        originatingPendingIntent);
+            }
+        }
+
+        @Override
+        public int startActivityInPackage(int uid, int realCallingPid, int realCallingUid,
+                String callingPackage, Intent intent, String resolvedType, IBinder resultTo,
+                String resultWho, int requestCode, int startFlags, SafeActivityOptions options,
+                int userId, TaskRecord inTask, String reason, boolean validateIncomingUser,
+                PendingIntentRecord originatingPendingIntent) {
+            synchronized (mGlobalLock) {
+                return getActivityStartController().startActivityInPackage(uid, realCallingPid,
+                        realCallingUid, callingPackage, intent, resolvedType, resultTo, resultWho,
+                        requestCode, startFlags, options, userId, inTask, reason,
+                        validateIncomingUser, originatingPendingIntent);
+            }
+        }
+
+        @Override
         public int startActivityAsUser(IApplicationThread caller, String callerPacakge,
                 Intent intent, Bundle options, int userId) {
             return ActivityTaskManagerService.this.startActivityAsUser(
@@ -5274,6 +5547,28 @@
         }
 
         @Override
+        public boolean isHeavyWeightProcess(WindowProcessController proc) {
+            synchronized (mGlobalLock) {
+                return proc == mHeavyWeightProcess;
+            }
+        }
+
+        @Override
+        public void clearHeavyWeightProcessIfEquals(WindowProcessController proc) {
+            synchronized (mGlobalLock) {
+                ActivityTaskManagerService.this.clearHeavyWeightProcessIfEquals(proc);
+            }
+        }
+
+        @Override
+        public void finishHeavyWeightApp() {
+            synchronized (mGlobalLock) {
+                ActivityTaskManagerService.this.clearHeavyWeightProcessIfEquals(
+                        mHeavyWeightProcess);
+            }
+        }
+
+        @Override
         public boolean isSleeping() {
             synchronized (mGlobalLock) {
                 return isSleepingLocked();
@@ -5382,6 +5677,7 @@
         @Override
         public void onPackageDataCleared(String name) {
             synchronized (mGlobalLock) {
+                mCompatModePackages.handlePackageDataClearedLocked(name);
                 mAppWarnings.onPackageDataCleared(name);
             }
         }
@@ -5390,6 +5686,98 @@
         public void onPackageUninstalled(String name) {
             synchronized (mGlobalLock) {
                 mAppWarnings.onPackageUninstalled(name);
+                mCompatModePackages.handlePackageUninstalledLocked(name);
+            }
+        }
+
+        @Override
+        public void onPackageAdded(String name, boolean replacing) {
+            synchronized (mGlobalLock) {
+                mCompatModePackages.handlePackageAddedLocked(name, replacing);
+            }
+        }
+
+        @Override
+        public CompatibilityInfo compatibilityInfoForPackage(ApplicationInfo ai) {
+            synchronized (mGlobalLock) {
+                return compatibilityInfoForPackageLocked(ai);
+            }
+        }
+
+        /**
+         * Set the corresponding display information for the process global configuration. To be
+         * called when we need to show IME on a different display.
+         *
+         * @param pid The process id associated with the IME window.
+         * @param displayId The ID of the display showing the IME.
+         */
+        @Override
+        public void onImeWindowSetOnDisplay(int pid, int displayId) {
+            if (pid == MY_PID || pid < 0) {
+                if (DEBUG_CONFIGURATION) {
+                    Slog.w(TAG,
+                            "Trying to update display configuration for system/invalid process.");
+                }
+                return;
+            }
+            mH.post(() -> {
+                synchronized (mGlobalLock) {
+                    // Check if display is initialized in AM.
+                    if (!mStackSupervisor.isDisplayAdded(displayId)) {
+                        // Call come when display is not yet added or has already been removed.
+                        if (DEBUG_CONFIGURATION) {
+                            Slog.w(TAG, "Trying to update display configuration for non-existing "
+                                            + "displayId=" + displayId);
+                        }
+                        return;
+                    }
+                    final WindowProcessController imeProcess = mPidMap.get(pid);
+                    if (imeProcess == null) {
+                        if (DEBUG_CONFIGURATION) {
+                            Slog.w(TAG, "Trying to update display configuration for invalid pid: "
+                                            + pid);
+                        }
+                        return;
+                    }
+                    // Fetch the current override configuration of the display and set it to the
+                    // process global configuration.
+                    imeProcess.onConfigurationChanged(
+                            mStackSupervisor.getDisplayOverrideConfiguration(displayId));
+                }
+            });
+        }
+
+        @Override
+        public void sendActivityResult(int callingUid, IBinder activityToken, String resultWho,
+                int requestCode, int resultCode, Intent data) {
+            synchronized (mGlobalLock) {
+                final ActivityRecord r = ActivityRecord.isInStackLocked(activityToken);
+                if (r != null && r.getStack() != null) {
+                    r.getStack().sendActivityResultLocked(callingUid, r, resultWho, requestCode,
+                            resultCode, data);
+                }
+            }
+        }
+
+        @Override
+        public void clearPendingResultForActivity(IBinder activityToken,
+                WeakReference<PendingIntentRecord> pir) {
+            synchronized (mGlobalLock) {
+                final ActivityRecord r = ActivityRecord.isInStackLocked(activityToken);
+                if (r != null && r.pendingResults != null) {
+                    r.pendingResults.remove(pir);
+                }
+            }
+        }
+
+        @Override
+        public IIntentSender getIntentSender(int type, String packageName,
+                int callingUid, int userId, IBinder token, String resultWho,
+                int requestCode, Intent[] intents, String[] resolvedTypes, int flags,
+                Bundle bOptions) {
+            synchronized (mGlobalLock) {
+                return getIntentSenderLocked(type, packageName, callingUid, userId, token,
+                        resultWho, requestCode, intents, resolvedTypes, flags, bOptions);
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 0a7e127..e2035f6 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -302,7 +302,7 @@
             mService.notifyPackageUse(r.intent.getComponent().getPackageName(),
                                       PackageManager.NOTIFY_PACKAGE_USE_BROADCAST_RECEIVER);
             app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
-                    mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
+                    mService.compatibilityInfoForPackage(r.curReceiver.applicationInfo),
                     r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
                     app.getReportedProcState());
             if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
@@ -741,7 +741,7 @@
 
         // Show a permission review UI only for explicit broadcast from a foreground app
         if (callerForeground && receiverRecord.intent.getComponent() != null) {
-            IIntentSender target = mService.getIntentSenderLocked(
+            IIntentSender target = mService.mPendingIntentController.getIntentSender(
                     ActivityManager.INTENT_SENDER_BROADCAST, receiverRecord.callerPackage,
                     receiverRecord.callingUid, receiverRecord.userId, null, null, 0,
                     new Intent[]{receiverRecord.intent},
@@ -1668,7 +1668,7 @@
 
     final boolean dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
             int opti, boolean dumpAll, String dumpPackage, boolean needSep) {
-        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
         if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
                 || mPendingBroadcast != null) {
             boolean printed = false;
diff --git a/services/core/java/com/android/server/am/CompatModePackages.java b/services/core/java/com/android/server/am/CompatModePackages.java
index 77efbfc..536f3a9 100644
--- a/services/core/java/com/android/server/am/CompatModePackages.java
+++ b/services/core/java/com/android/server/am/CompatModePackages.java
@@ -51,13 +51,13 @@
     private static final String TAG = TAG_WITH_CLASS_NAME ? "CompatModePackages" : TAG_AM;
     private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
 
-    private final ActivityManagerService mService;
+    private final ActivityTaskManagerService mService;
     private final AtomicFile mFile;
 
     // Compatibility state: no longer ask user to select the mode.
-    public static final int COMPAT_FLAG_DONT_ASK = 1<<0;
+    private static final int COMPAT_FLAG_DONT_ASK = 1<<0;
     // Compatibility state: compatibility mode is enabled.
-    public static final int COMPAT_FLAG_ENABLED = 1<<1;
+    private static final int COMPAT_FLAG_ENABLED = 1<<1;
 
     private final HashMap<String, Integer> mPackages = new HashMap<String, Integer>();
 
@@ -80,7 +80,7 @@
         }
     };
 
-    public CompatModePackages(ActivityManagerService service, File systemDir, Handler handler) {
+    public CompatModePackages(ActivityTaskManagerService service, File systemDir, Handler handler) {
         mService = service;
         mFile = new AtomicFile(new File(systemDir, "packages-compat.xml"), "compat-mode");
         mHandler = new CompatHandler(handler.getLooper());
@@ -317,12 +317,12 @@
 
             scheduleWrite();
 
-            final ActivityStack stack = mService.mActivityTaskManager.getTopDisplayFocusedStack();
+            final ActivityStack stack = mService.getTopDisplayFocusedStack();
             ActivityRecord starting = stack.restartPackage(packageName);
 
             // Tell all processes that loaded this package about the change.
-            for (int i=mService.mLruProcesses.size()-1; i>=0; i--) {
-                ProcessRecord app = mService.mLruProcesses.get(i);
+            for (int i = mService.mAm.mLruProcesses.size() - 1; i >= 0; i--) {
+                final ProcessRecord app = mService.mAm.mLruProcesses.get(i);
                 if (!app.pkgList.containsKey(packageName)) {
                     continue;
                 }
@@ -346,10 +346,10 @@
         }
     }
 
-    void saveCompatModes() {
+    private void saveCompatModes() {
         HashMap<String, Integer> pkgs;
-        synchronized (mService) {
-            pkgs = new HashMap<String, Integer>(mPackages);
+        synchronized (mService.mGlobalLock) {
+            pkgs = new HashMap<>(mPackages);
         }
 
         FileOutputStream fos = null;
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index ee4e36f..cfe2829 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -29,16 +29,20 @@
 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
+
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
-import static com.android.server.am.KeyguardControllerProto.KEYGUARD_OCCLUDED;
+import static com.android.server.am.KeyguardControllerProto.KEYGUARD_OCCLUDED_STATES;
 import static com.android.server.am.KeyguardControllerProto.KEYGUARD_SHOWING;
+import static com.android.server.am.KeyguardOccludedProto.DISPLAY_ID;
+import static com.android.server.am.KeyguardOccludedProto.KEYGUARD_OCCLUDED;
 
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.Trace;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.policy.IKeyguardDismissCallback;
@@ -58,19 +62,18 @@
 
     private static final String TAG = TAG_WITH_CLASS_NAME ? "KeyguardController" : TAG_AM;
 
-    private final ActivityTaskManagerService mService;
     private final ActivityStackSupervisor mStackSupervisor;
     private WindowManagerService mWindowManager;
     private boolean mKeyguardShowing;
     private boolean mAodShowing;
     private boolean mKeyguardGoingAway;
-    private boolean mOccluded;
     private boolean mDismissalRequested;
-    private ActivityRecord mDismissingKeyguardActivity;
     private int mBeforeUnoccludeTransit;
     private int mVisibilityTransactionDepth;
-    private SleepToken mSleepToken;
+    // TODO(b/111955725): Support multiple external displays
     private int mSecondaryDisplayShowing = INVALID_DISPLAY;
+    private final SparseArray<KeyguardDisplayState> mDisplayStates = new SparseArray<>();
+    private final ActivityTaskManagerService mService;
 
     KeyguardController(ActivityTaskManagerService service,
             ActivityStackSupervisor stackSupervisor) {
@@ -87,8 +90,8 @@
      *         on the given display, false otherwise
      */
     boolean isKeyguardOrAodShowing(int displayId) {
-        return (mKeyguardShowing || mAodShowing) && !mKeyguardGoingAway &&
-                (displayId == DEFAULT_DISPLAY ? !mOccluded : displayId == mSecondaryDisplayShowing);
+        return (mKeyguardShowing || mAodShowing) && !mKeyguardGoingAway
+                && !isDisplayOccluded(displayId);
     }
 
     /**
@@ -96,8 +99,7 @@
      *         display, false otherwise
      */
     boolean isKeyguardShowing(int displayId) {
-        return mKeyguardShowing && !mKeyguardGoingAway &&
-                (displayId == DEFAULT_DISPLAY ? !mOccluded : displayId == mSecondaryDisplayShowing);
+        return mKeyguardShowing && !mKeyguardGoingAway && !isDisplayOccluded(displayId);
     }
 
     /**
@@ -133,6 +135,7 @@
         if (showingChanged) {
             dismissDockedStackIfNeeded();
             setKeyguardGoingAway(false);
+            // TODO(b/113840485): Check usage for non-default display
             mWindowManager.setKeyguardOrAodShowingOnDefaultDisplay(
                     isKeyguardOrAodShowing(DEFAULT_DISPLAY));
             if (keyguardShowing) {
@@ -248,7 +251,8 @@
         // already the dismissing activity, in which case we don't allow it to repeatedly dismiss
         // Keyguard.
         return dismissKeyguard && canDismissKeyguard() && !mAodShowing
-                && (mDismissalRequested || r != mDismissingKeyguardActivity);
+                && (mDismissalRequested
+                || getDisplay(r.getDisplayId()).mDismissingKeyguardActivity != r);
     }
 
     /**
@@ -259,44 +263,16 @@
     }
 
     private void visibilitiesUpdated() {
-        final boolean lastOccluded = mOccluded;
-        final ActivityRecord lastDismissingKeyguardActivity = mDismissingKeyguardActivity;
-        mOccluded = false;
-        mDismissingKeyguardActivity = null;
-
+        boolean requestDismissKeyguard = false;
         for (int displayNdx = mStackSupervisor.getChildCount() - 1; displayNdx >= 0; displayNdx--) {
             final ActivityDisplay display = mStackSupervisor.getChildAt(displayNdx);
-            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getChildAt(stackNdx);
-
-                // Only the top activity of the focused stack on the default display may control
-                // occluded state.
-                if (display.mDisplayId == DEFAULT_DISPLAY
-                        && mStackSupervisor.isTopDisplayFocusedStack(stack)) {
-
-                    // A dismissing activity occludes Keyguard in the insecure case for legacy
-                    // reasons.
-                    final ActivityRecord topDismissing = stack.getTopDismissingKeyguardActivity();
-                    mOccluded =
-                            stack.topActivityOccludesKeyguard()
-                                    || (topDismissing != null
-                                            && stack.topRunningActivityLocked() == topDismissing
-                                            && canShowWhileOccluded(
-                                                    true /* dismissKeyguard */,
-                                                    false /* showWhenLocked */));
-                }
-
-                if (mDismissingKeyguardActivity == null
-                        && stack.getTopDismissingKeyguardActivity() != null) {
-                    mDismissingKeyguardActivity = stack.getTopDismissingKeyguardActivity();
-                }
-            }
+            final KeyguardDisplayState state = getDisplay(display.mDisplayId);
+            state.visibilitiesUpdated(this, display);
+            requestDismissKeyguard |= state.mRequestDismissKeyguard;
         }
-        mOccluded |= mWindowManager.isShowingDream();
-        if (mOccluded != lastOccluded) {
-            handleOccludedChanged();
-        }
-        if (mDismissingKeyguardActivity != lastDismissingKeyguardActivity) {
+
+        // Dismissing Keyguard happens globally using the information from all displays.
+        if (requestDismissKeyguard) {
             handleDismissKeyguard();
         }
     }
@@ -305,7 +281,7 @@
      * Called when occluded state changed.
      */
     private void handleOccludedChanged() {
-        mWindowManager.onKeyguardOccludedChanged(mOccluded);
+        mWindowManager.onKeyguardOccludedChanged(isDisplayOccluded(DEFAULT_DISPLAY));
         if (isKeyguardLocked()) {
             mWindowManager.deferSurfaceLayout();
             try {
@@ -322,14 +298,13 @@
     }
 
     /**
-     * Called when somebody might want to dismiss the Keyguard.
+     * Called when somebody wants to dismiss the Keyguard via the flag.
      */
     private void handleDismissKeyguard() {
         // We only allow dismissing Keyguard via the flag when Keyguard is secure for legacy
         // reasons, because that's how apps used to dismiss Keyguard in the secure case. In the
         // insecure case, we actually show it on top of the lockscreen. See #canShowWhileOccluded.
-        if (!mOccluded && mDismissingKeyguardActivity != null
-                && mWindowManager.isKeyguardSecure()) {
+        if (mWindowManager.isKeyguardSecure()) {
             mWindowManager.dismissKeyguard(null /* callback */, null /* message */);
             mDismissalRequested = true;
 
@@ -345,6 +320,10 @@
         }
     }
 
+    private boolean isDisplayOccluded(int displayId) {
+        return getDisplay(displayId).mOccluded;
+    }
+
     /**
      * @return true if Keyguard can be currently dismissed without entering credentials.
      */
@@ -355,12 +334,14 @@
     private int resolveOccludeTransit() {
         if (mBeforeUnoccludeTransit != TRANSIT_UNSET
                 && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
-                && mOccluded) {
+                // TODO(b/113840485): Handle app transition for individual display.
+                && isDisplayOccluded(DEFAULT_DISPLAY)) {
 
             // Reuse old transit in case we are occluding Keyguard again, meaning that we never
             // actually occclude/unocclude Keyguard, but just run a normal transition.
             return mBeforeUnoccludeTransit;
-        } else if (!mOccluded) {
+            // TODO(b/113840485): Handle app transition for individual display.
+        } else if (!isDisplayOccluded(DEFAULT_DISPLAY)) {
 
             // Save transit in case we dismiss/occlude Keyguard shortly after.
             mBeforeUnoccludeTransit = mWindowManager.getPendingAppTransition();
@@ -371,7 +352,8 @@
     }
 
     private void dismissDockedStackIfNeeded() {
-        if (mKeyguardShowing && mOccluded) {
+        // TODO(b/113840485): Handle docked stack for individual display.
+        if (mKeyguardShowing && isDisplayOccluded(DEFAULT_DISPLAY)) {
             // The lock screen is currently showing, but is occluded by a window that can
             // show on top of the lock screen. In this can we want to dismiss the docked
             // stack since it will be complicated/risky to try to put the activity on top
@@ -386,11 +368,116 @@
     }
 
     private void updateKeyguardSleepToken() {
-        if (mSleepToken == null && isKeyguardOrAodShowing(DEFAULT_DISPLAY)) {
-            mSleepToken = mService.acquireSleepToken("Keyguard", DEFAULT_DISPLAY);
-        } else if (mSleepToken != null && !isKeyguardOrAodShowing(DEFAULT_DISPLAY)) {
-            mSleepToken.release();
-            mSleepToken = null;
+        for (int displayNdx = mStackSupervisor.getChildCount() - 1; displayNdx >= 0; displayNdx--) {
+            final ActivityDisplay display = mStackSupervisor.getChildAt(displayNdx);
+            final KeyguardDisplayState state = getDisplay(display.mDisplayId);
+            if (isKeyguardOrAodShowing(display.mDisplayId) && state.mSleepToken == null) {
+                state.acquiredSleepToken();
+            } else if (!isKeyguardOrAodShowing(display.mDisplayId) && state.mSleepToken != null) {
+                state.releaseSleepToken();
+            }
+        }
+    }
+
+    private KeyguardDisplayState getDisplay(int displayId) {
+        if (mDisplayStates.get(displayId) == null) {
+            mDisplayStates.append(displayId,
+                    new KeyguardDisplayState(mService, displayId));
+        }
+        return mDisplayStates.get(displayId);
+    }
+
+    void onDisplayRemoved(int displayId) {
+        if (mDisplayStates.get(displayId) != null) {
+            mDisplayStates.get(displayId).onRemoved();
+            mDisplayStates.remove(displayId);
+        }
+    }
+
+    /** Represents Keyguard state per individual display. */
+    private static class KeyguardDisplayState {
+        private final int mDisplayId;
+        private boolean mOccluded;
+        private ActivityRecord mDismissingKeyguardActivity;
+        private boolean mRequestDismissKeyguard;
+        private final ActivityTaskManagerService mService;
+        private SleepToken mSleepToken;
+
+        KeyguardDisplayState(ActivityTaskManagerService service, int displayId) {
+            mService = service;
+            mDisplayId = displayId;
+        }
+
+        void onRemoved() {
+            mDismissingKeyguardActivity = null;
+            releaseSleepToken();
+        }
+
+        void acquiredSleepToken() {
+            if (mSleepToken == null) {
+                mSleepToken = mService.acquireSleepToken("keyguard", mDisplayId);
+            }
+        }
+
+        void releaseSleepToken() {
+            if (mSleepToken != null) {
+                mSleepToken.release();
+                mSleepToken = null;
+            }
+        }
+
+        void visibilitiesUpdated(KeyguardController controller, ActivityDisplay display) {
+            final boolean lastOccluded = mOccluded;
+            final ActivityRecord lastDismissActivity = mDismissingKeyguardActivity;
+            mRequestDismissKeyguard = false;
+            mOccluded = false;
+            mDismissingKeyguardActivity = null;
+
+            // Only the top activity of the focused stack on each display may control it's
+            // occluded state.
+            final ActivityStack focusedStack = display.getFocusedStack();
+            if (focusedStack != null) {
+                final ActivityRecord topDismissing =
+                        focusedStack.getTopDismissingKeyguardActivity();
+                mOccluded = focusedStack.topActivityOccludesKeyguard() || (topDismissing != null
+                                && focusedStack.topRunningActivityLocked() == topDismissing
+                                && controller.canShowWhileOccluded(
+                                true /* dismissKeyguard */,
+                                false /* showWhenLocked */));
+                if (focusedStack.getTopDismissingKeyguardActivity() != null) {
+                    mDismissingKeyguardActivity = focusedStack.getTopDismissingKeyguardActivity();
+                }
+                mOccluded |= controller.mWindowManager.isShowingDream();
+            }
+
+            // TODO(b/113840485): Handle app transition for individual display.
+            // For now, only default display can change occluded.
+            if (lastOccluded != mOccluded && mDisplayId == DEFAULT_DISPLAY) {
+                controller.handleOccludedChanged();
+            }
+            if (lastDismissActivity != mDismissingKeyguardActivity && !mOccluded
+                    && mDismissingKeyguardActivity != null
+                    && controller.mWindowManager.isKeyguardSecure()) {
+                mRequestDismissKeyguard = true;
+            }
+        }
+
+        void dumpStatus(PrintWriter pw, String prefix) {
+            final StringBuilder sb = new StringBuilder();
+            sb.append(prefix);
+            sb.append("  Occluded=").append(mOccluded)
+                    .append(" DismissingKeyguardActivity=")
+                    .append(mDismissingKeyguardActivity)
+                    .append(" at display=")
+                    .append(mDisplayId);
+            pw.println(sb.toString());
+        }
+
+        void writeToProto(ProtoOutputStream proto, long fieldId) {
+            final long token = proto.start(fieldId);
+            proto.write(DISPLAY_ID, mDisplayId);
+            proto.write(KEYGUARD_OCCLUDED, mOccluded);
+            proto.end(token);
         }
     }
 
@@ -399,8 +486,7 @@
         pw.println(prefix + "  mKeyguardShowing=" + mKeyguardShowing);
         pw.println(prefix + "  mAodShowing=" + mAodShowing);
         pw.println(prefix + "  mKeyguardGoingAway=" + mKeyguardGoingAway);
-        pw.println(prefix + "  mOccluded=" + mOccluded);
-        pw.println(prefix + "  mDismissingKeyguardActivity=" + mDismissingKeyguardActivity);
+        dumpDisplayStates(pw, prefix);
         pw.println(prefix + "  mDismissalRequested=" + mDismissalRequested);
         pw.println(prefix + "  mVisibilityTransactionDepth=" + mVisibilityTransactionDepth);
     }
@@ -408,7 +494,19 @@
     void writeToProto(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         proto.write(KEYGUARD_SHOWING, mKeyguardShowing);
-        proto.write(KEYGUARD_OCCLUDED, mOccluded);
+        writeDisplayStatesToProto(proto, KEYGUARD_OCCLUDED_STATES);
         proto.end(token);
     }
+
+    private void dumpDisplayStates(PrintWriter pw, String prefix) {
+        for (int i = 0; i < mDisplayStates.size(); i++) {
+            mDisplayStates.valueAt(i).dumpStatus(pw, prefix);
+        }
+    }
+
+    private void writeDisplayStatesToProto(ProtoOutputStream proto, long fieldId) {
+        for (int i = 0; i < mDisplayStates.size(); i++) {
+            mDisplayStates.valueAt(i).writeToProto(proto, fieldId);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/am/MemoryStatUtil.java b/services/core/java/com/android/server/am/MemoryStatUtil.java
index f9dccea0..228c71d 100644
--- a/services/core/java/com/android/server/am/MemoryStatUtil.java
+++ b/services/core/java/com/android/server/am/MemoryStatUtil.java
@@ -22,6 +22,7 @@
 
 import android.annotation.Nullable;
 import android.os.FileUtils;
+import android.os.SystemProperties;
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -36,14 +37,25 @@
  * Static utility methods related to {@link MemoryStat}.
  */
 final class MemoryStatUtil {
+    static final int BYTES_IN_KILOBYTE = 1024;
+
     private static final String TAG = TAG_WITH_CLASS_NAME ? "MemoryStatUtil" : TAG_AM;
 
+    /** True if device has per-app memcg */
+    private static final boolean DEVICE_HAS_PER_APP_MEMCG =
+            SystemProperties.getBoolean("ro.config.per_app_memcg", false);
+
     /** Path to check if device has memcg */
     private static final String MEMCG_TEST_PATH = "/dev/memcg/apps/memory.stat";
     /** Path to memory stat file for logging app start memory state */
     private static final String MEMORY_STAT_FILE_FMT = "/dev/memcg/apps/uid_%d/pid_%d/memory.stat";
+    /** Path to memory max usage file for logging app memory state */
+    private static final String MEMORY_MAX_USAGE_FILE_FMT =
+            "/dev/memcg/apps/uid_%d/pid_%d/memory.max_usage_in_bytes";
     /** Path to procfs stat file for logging app start memory state */
     private static final String PROC_STAT_FILE_FMT = "/proc/%d/stat";
+    /** Path to procfs status file for logging app memory state */
+    private static final String PROC_STATUS_FILE_FMT = "/proc/%d/status";
 
     private static final Pattern PGFAULT = Pattern.compile("total_pgfault (\\d+)");
     private static final Pattern PGMAJFAULT = Pattern.compile("total_pgmajfault (\\d+)");
@@ -51,19 +63,19 @@
     private static final Pattern CACHE_IN_BYTES = Pattern.compile("total_cache (\\d+)");
     private static final Pattern SWAP_IN_BYTES = Pattern.compile("total_swap (\\d+)");
 
+    private static final Pattern RSS_HIGH_WATERMARK_IN_BYTES =
+            Pattern.compile("VmHWM:\\s*(\\d+)\\s*kB");
+
     private static final int PGFAULT_INDEX = 9;
     private static final int PGMAJFAULT_INDEX = 11;
     private static final int RSS_IN_BYTES_INDEX = 23;
 
-    /** True if device has memcg */
-    private static volatile Boolean sDeviceHasMemCg;
-
     private MemoryStatUtil() {}
 
     /**
      * Reads memory stat for a process.
      *
-     * Reads from memcg if available on device, else fallback to procfs.
+     * Reads from per-app memcg if available on device, else fallback to procfs.
      * Returns null if no stats can be read.
      */
     @Nullable
@@ -78,8 +90,15 @@
      */
     @Nullable
     static MemoryStat readMemoryStatFromMemcg(int uid, int pid) {
-        final String path = String.format(Locale.US, MEMORY_STAT_FILE_FMT, uid, pid);
-        return parseMemoryStatFromMemcg(readFileContents(path));
+        final String statPath = String.format(Locale.US, MEMORY_STAT_FILE_FMT, uid, pid);
+        MemoryStat stat = parseMemoryStatFromMemcg(readFileContents(statPath));
+        if (stat == null) {
+            return null;
+        }
+        String maxUsagePath = String.format(Locale.US, MEMORY_MAX_USAGE_FILE_FMT, uid, pid);
+        stat.rssHighWatermarkInBytes = parseMemoryMaxUsageFromMemCg(
+                readFileContents(maxUsagePath));
+        return stat;
     }
 
     /**
@@ -89,8 +108,14 @@
      */
     @Nullable
     static MemoryStat readMemoryStatFromProcfs(int pid) {
-        final String path = String.format(Locale.US, PROC_STAT_FILE_FMT, pid);
-        return parseMemoryStatFromProcfs(readFileContents(path));
+        final String statPath = String.format(Locale.US, PROC_STAT_FILE_FMT, pid);
+        MemoryStat stat = parseMemoryStatFromProcfs(readFileContents(statPath));
+        if (stat == null) {
+            return null;
+        }
+        final String statusPath = String.format(Locale.US, PROC_STATUS_FILE_FMT, pid);
+        stat.rssHighWatermarkInBytes = parseVmHWMFromProcfs(readFileContents(statusPath));
+        return stat;
     }
 
     private static String readFileContents(String path) {
@@ -111,7 +136,7 @@
     /**
      * Parses relevant statistics out from the contents of a memory.stat file in memcg.
      */
-    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+    @VisibleForTesting
     @Nullable
     static MemoryStat parseMemoryStatFromMemcg(String memoryStatContents) {
         if (memoryStatContents == null || memoryStatContents.isEmpty()) {
@@ -133,10 +158,18 @@
         return memoryStat;
     }
 
+    @VisibleForTesting
+    static long parseMemoryMaxUsageFromMemCg(String memoryMaxUsageContents) {
+        if (memoryMaxUsageContents == null || memoryMaxUsageContents.isEmpty()) {
+            return 0;
+        }
+        return Long.valueOf(memoryMaxUsageContents);
+    }
+
     /**
-     * Parses relevant statistics out from the contents of a /proc/pid/stat file in procfs.
+     * Parses relevant statistics out from the contents of the /proc/pid/stat file in procfs.
      */
-    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+    @VisibleForTesting
     @Nullable
     static MemoryStat parseMemoryStatFromProcfs(String procStatContents) {
         if (procStatContents == null || procStatContents.isEmpty()) {
@@ -156,15 +189,24 @@
     }
 
     /**
-     * Checks if memcg is available on device.
-     *
-     * Touches the filesystem to do the check.
+     * Parses RSS high watermark out from the contents of the /proc/pid/status file in procfs. The
+     * returned value is in bytes.
+     */
+    @VisibleForTesting
+    static long parseVmHWMFromProcfs(String procStatusContents) {
+        if (procStatusContents == null || procStatusContents.isEmpty()) {
+            return 0;
+        }
+        Matcher m = RSS_HIGH_WATERMARK_IN_BYTES.matcher(procStatusContents);
+        // Convert value read from /proc/pid/status from kilobytes to bytes.
+        return m.find() ? Long.valueOf(m.group(1)) * BYTES_IN_KILOBYTE : 0;
+    }
+
+    /**
+     * Returns whether per-app memcg is available on device.
      */
     static boolean hasMemcg() {
-        if (sDeviceHasMemCg == null) {
-            sDeviceHasMemCg = (new File(MEMCG_TEST_PATH)).exists();
-        }
-        return sDeviceHasMemCg;
+        return DEVICE_HAS_PER_APP_MEMCG;
     }
 
     static final class MemoryStat {
@@ -178,5 +220,7 @@
         long cacheInBytes;
         /** Number of bytes of swap usage */
         long swapInBytes;
+        /** Number of bytes of peak anonymous and swap cache memory */
+        long rssHighWatermarkInBytes;
     }
 }
diff --git a/services/core/java/com/android/server/am/OomAdjProfiler.java b/services/core/java/com/android/server/am/OomAdjProfiler.java
index 6230e0d..71f0db5 100644
--- a/services/core/java/com/android/server/am/OomAdjProfiler.java
+++ b/services/core/java/com/android/server/am/OomAdjProfiler.java
@@ -91,9 +91,9 @@
                 return;
             }
             mSystemServerCpuTimeUpdateScheduled = true;
-            BackgroundThread.getHandler().post(PooledLambda.obtainRunnable(
+            BackgroundThread.getHandler().sendMessage(PooledLambda.obtainMessage(
                     OomAdjProfiler::updateSystemServerCpuTime,
-                    this, mOnBattery, mScreenOff).recycleOnUse());
+                    this, mOnBattery, mScreenOff));
         }
     }
 
diff --git a/services/core/java/com/android/server/am/PendingIntentController.java b/services/core/java/com/android/server/am/PendingIntentController.java
new file mode 100644
index 0000000..a9c00a7
--- /dev/null
+++ b/services/core/java/com/android/server/am/PendingIntentController.java
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.am;
+
+import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
+import android.app.Activity;
+import android.app.ActivityManagerInternal;
+import android.app.AppGlobals;
+import android.app.PendingIntent;
+import android.content.IIntentSender;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.Slog;
+import com.android.internal.os.IResultReceiver;
+import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.server.LocalServices;
+import com.android.server.wm.ActivityTaskManagerInternal;
+
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * Helper class for {@link ActivityManagerService} responsible for managing pending intents.
+ *
+ * <p>This class uses {@link #mLock} to synchronize access to internal state and doesn't make use of
+ * {@link ActivityManagerService} lock since there can be direct calls into this class from outside
+ * AM. This helps avoid deadlocks.
+ */
+public class PendingIntentController {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentController" : TAG_AM;
+    private static final String TAG_MU = TAG + POSTFIX_MU;
+
+    /** Lock for internal state. */
+    final Object mLock = new Object();
+    final Handler mH;
+    ActivityManagerInternal mAmInternal;
+    final UserController mUserController;
+    final ActivityTaskManagerInternal mAtmInternal;
+
+    /** Set of IntentSenderRecord objects that are currently active. */
+    final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
+            = new HashMap<>();
+
+    PendingIntentController(Looper looper, UserController userController) {
+        mH = new Handler(looper);
+        mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
+        mUserController = userController;
+    }
+
+    void onActivityManagerInternalAdded() {
+        synchronized (mLock) {
+            mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
+        }
+    }
+
+    PendingIntentRecord getIntentSender(int type, String packageName, int callingUid, int userId,
+            IBinder token, String resultWho, int requestCode, Intent[] intents,
+            String[] resolvedTypes, int flags, Bundle bOptions) {
+        synchronized (mLock) {
+            if (DEBUG_MU) Slog.v(TAG_MU, "getIntentSender(): uid=" + callingUid);
+
+            // We're going to be splicing together extras before sending, so we're
+            // okay poking into any contained extras.
+            if (intents != null) {
+                for (int i = 0; i < intents.length; i++) {
+                    intents[i].setDefusable(true);
+                }
+            }
+            Bundle.setDefusable(bOptions, true);
+
+            final boolean noCreate = (flags & PendingIntent.FLAG_NO_CREATE) != 0;
+            final boolean cancelCurrent = (flags & PendingIntent.FLAG_CANCEL_CURRENT) != 0;
+            final boolean updateCurrent = (flags & PendingIntent.FLAG_UPDATE_CURRENT) != 0;
+            flags &= ~(PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_CANCEL_CURRENT
+                    | PendingIntent.FLAG_UPDATE_CURRENT);
+
+            PendingIntentRecord.Key key = new PendingIntentRecord.Key(type, packageName, token,
+                    resultWho, requestCode, intents, resolvedTypes, flags,
+                    SafeActivityOptions.fromBundle(bOptions), userId);
+            WeakReference<PendingIntentRecord> ref;
+            ref = mIntentSenderRecords.get(key);
+            PendingIntentRecord rec = ref != null ? ref.get() : null;
+            if (rec != null) {
+                if (!cancelCurrent) {
+                    if (updateCurrent) {
+                        if (rec.key.requestIntent != null) {
+                            rec.key.requestIntent.replaceExtras(intents != null ?
+                                    intents[intents.length - 1] : null);
+                        }
+                        if (intents != null) {
+                            intents[intents.length - 1] = rec.key.requestIntent;
+                            rec.key.allIntents = intents;
+                            rec.key.allResolvedTypes = resolvedTypes;
+                        } else {
+                            rec.key.allIntents = null;
+                            rec.key.allResolvedTypes = null;
+                        }
+                    }
+                    return rec;
+                }
+                makeIntentSenderCanceled(rec);
+                mIntentSenderRecords.remove(key);
+            }
+            if (noCreate) {
+                return rec;
+            }
+            rec = new PendingIntentRecord(this, key, callingUid);
+            mIntentSenderRecords.put(key, rec.ref);
+            return rec;
+        }
+    }
+
+    boolean removePendingIntentsForPackage(String packageName, int userId, int appId,
+            boolean doIt) {
+
+        boolean didSomething = false;
+        synchronized (mLock) {
+
+            // Remove pending intents.  For now we only do this when force stopping users, because
+            // we have some problems when doing this for packages -- app widgets are not currently
+            // cleaned up for such packages, so they can be left with bad pending intents.
+            if (mIntentSenderRecords.size() <= 0) {
+                return false;
+            }
+
+            Iterator<WeakReference<PendingIntentRecord>> it
+                    = mIntentSenderRecords.values().iterator();
+            while (it.hasNext()) {
+                WeakReference<PendingIntentRecord> wpir = it.next();
+                if (wpir == null) {
+                    it.remove();
+                    continue;
+                }
+                PendingIntentRecord pir = wpir.get();
+                if (pir == null) {
+                    it.remove();
+                    continue;
+                }
+                if (packageName == null) {
+                    // Stopping user, remove all objects for the user.
+                    if (pir.key.userId != userId) {
+                        // Not the same user, skip it.
+                        continue;
+                    }
+                } else {
+                    if (UserHandle.getAppId(pir.uid) != appId) {
+                        // Different app id, skip it.
+                        continue;
+                    }
+                    if (userId != UserHandle.USER_ALL && pir.key.userId != userId) {
+                        // Different user, skip it.
+                        continue;
+                    }
+                    if (!pir.key.packageName.equals(packageName)) {
+                        // Different package, skip it.
+                        continue;
+                    }
+                }
+                if (!doIt) {
+                    return true;
+                }
+                didSomething = true;
+                it.remove();
+                makeIntentSenderCanceled(pir);
+                if (pir.key.activity != null) {
+                    final Message m = PooledLambda.obtainMessage(
+                            PendingIntentController::clearPendingResultForActivity, this,
+                            pir.key.activity, pir.ref);
+                    mH.sendMessage(m);
+                }
+            }
+        }
+
+        return didSomething;
+    }
+
+    public void cancelIntentSender(IIntentSender sender) {
+        if (!(sender instanceof PendingIntentRecord)) {
+            return;
+        }
+        synchronized (mLock) {
+            final PendingIntentRecord rec = (PendingIntentRecord) sender;
+            try {
+                final int uid = AppGlobals.getPackageManager().getPackageUid(rec.key.packageName,
+                        MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getCallingUserId());
+                if (!UserHandle.isSameApp(uid, Binder.getCallingUid())) {
+                    String msg = "Permission Denial: cancelIntentSender() from pid="
+                            + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+                            + " is not allowed to cancel package " + rec.key.packageName;
+                    Slog.w(TAG, msg);
+                    throw new SecurityException(msg);
+                }
+            } catch (RemoteException e) {
+                throw new SecurityException(e);
+            }
+            cancelIntentSender(rec, true);
+        }
+    }
+
+    public void cancelIntentSender(PendingIntentRecord rec, boolean cleanActivity) {
+        synchronized (mLock) {
+            makeIntentSenderCanceled(rec);
+            mIntentSenderRecords.remove(rec.key);
+            if (cleanActivity && rec.key.activity != null) {
+                final Message m = PooledLambda.obtainMessage(
+                        PendingIntentController::clearPendingResultForActivity, this,
+                        rec.key.activity, rec.ref);
+                mH.sendMessage(m);
+            }
+        }
+    }
+
+    private void makeIntentSenderCanceled(PendingIntentRecord rec) {
+        rec.canceled = true;
+        final RemoteCallbackList<IResultReceiver> callbacks = rec.detachCancelListenersLocked();
+        if (callbacks != null) {
+            final Message m = PooledLambda.obtainMessage(
+                    PendingIntentController::handlePendingIntentCancelled, this, callbacks);
+            mH.sendMessage(m);
+        }
+    }
+
+    private void handlePendingIntentCancelled(RemoteCallbackList<IResultReceiver> callbacks) {
+        int N = callbacks.beginBroadcast();
+        for (int i = 0; i < N; i++) {
+            try {
+                callbacks.getBroadcastItem(i).send(Activity.RESULT_CANCELED, null);
+            } catch (RemoteException e) {
+                // Process is not longer running...whatever.
+            }
+        }
+        callbacks.finishBroadcast();
+        // We have to clean up the RemoteCallbackList here, because otherwise it will
+        // needlessly hold the enclosed callbacks until the remote process dies.
+        callbacks.kill();
+    }
+
+    private void clearPendingResultForActivity(IBinder activityToken,
+            WeakReference<PendingIntentRecord> pir) {
+        mAtmInternal.clearPendingResultForActivity(activityToken, pir);
+    }
+
+    void dumpPendingIntents(PrintWriter pw, boolean dumpAll, String dumpPackage) {
+        synchronized (mLock) {
+            boolean printed = false;
+
+            pw.println("ACTIVITY MANAGER PENDING INTENTS (dumpsys activity intents)");
+
+            if (mIntentSenderRecords.size() > 0) {
+                // Organize these by package name, so they are easier to read.
+                final ArrayMap<String, ArrayList<PendingIntentRecord>> byPackage = new ArrayMap<>();
+                final ArrayList<WeakReference<PendingIntentRecord>> weakRefs = new ArrayList<>();
+                final Iterator<WeakReference<PendingIntentRecord>> it
+                        = mIntentSenderRecords.values().iterator();
+                while (it.hasNext()) {
+                    WeakReference<PendingIntentRecord> ref = it.next();
+                    PendingIntentRecord rec = ref != null ? ref.get() : null;
+                    if (rec == null) {
+                        weakRefs.add(ref);
+                        continue;
+                    }
+                    if (dumpPackage != null && !dumpPackage.equals(rec.key.packageName)) {
+                        continue;
+                    }
+                    ArrayList<PendingIntentRecord> list = byPackage.get(rec.key.packageName);
+                    if (list == null) {
+                        list = new ArrayList<>();
+                        byPackage.put(rec.key.packageName, list);
+                    }
+                    list.add(rec);
+                }
+                for (int i = 0; i < byPackage.size(); i++) {
+                    ArrayList<PendingIntentRecord> intents = byPackage.valueAt(i);
+                    printed = true;
+                    pw.print("  * "); pw.print(byPackage.keyAt(i));
+                    pw.print(": "); pw.print(intents.size()); pw.println(" items");
+                    for (int j = 0; j < intents.size(); j++) {
+                        pw.print("    #"); pw.print(j); pw.print(": "); pw.println(intents.get(j));
+                        if (dumpAll) {
+                            intents.get(j).dump(pw, "      ");
+                        }
+                    }
+                }
+                if (weakRefs.size() > 0) {
+                    printed = true;
+                    pw.println("  * WEAK REFS:");
+                    for (int i = 0; i < weakRefs.size(); i++) {
+                        pw.print("    #"); pw.print(i); pw.print(": "); pw.println(weakRefs.get(i));
+                    }
+                }
+            }
+
+            if (!printed) {
+                pw.println("  (nothing)");
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index ee1166e..b9c6fa6 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -38,15 +38,16 @@
 import android.util.TimeUtils;
 
 import com.android.internal.os.IResultReceiver;
+import com.android.internal.util.function.pooled.PooledLambda;
 
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.Objects;
 
-final class PendingIntentRecord extends IIntentSender.Stub {
+public final class PendingIntentRecord extends IIntentSender.Stub {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentRecord" : TAG_AM;
 
-    final ActivityManagerService owner;
+    final PendingIntentController controller;
     final Key key;
     final int uid;
     final WeakReference<PendingIntentRecord> ref;
@@ -62,7 +63,7 @@
     final static class Key {
         final int type;
         final String packageName;
-        final ActivityRecord activity;
+        final IBinder activity;
         final String who;
         final int requestCode;
         final Intent requestIntent;
@@ -76,7 +77,7 @@
 
         private static final int ODD_PRIME_NUMBER = 37;
 
-        Key(int _t, String _p, ActivityRecord _a, String _w,
+        Key(int _t, String _p, IBinder _a, String _w,
                 int _r, Intent[] _i, String[] _it, int _f, SafeActivityOptions _o, int _userId) {
             type = _t;
             packageName = _p;
@@ -114,6 +115,7 @@
             //        + Integer.toHexString(hashCode));
         }
 
+        @Override
         public boolean equals(Object otherObj) {
             if (otherObj == null) {
                 return false;
@@ -188,11 +190,11 @@
         }
     }
 
-    PendingIntentRecord(ActivityManagerService _owner, Key _k, int _u) {
-        owner = _owner;
+    PendingIntentRecord(PendingIntentController _controller, Key _k, int _u) {
+        controller = _controller;
         key = _k;
         uid = _u;
-        ref = new WeakReference<PendingIntentRecord>(this);
+        ref = new WeakReference<>(this);
     }
 
     void setWhitelistDurationLocked(IBinder whitelistToken, long duration) {
@@ -247,189 +249,196 @@
     }
 
     int sendInner(int code, Intent intent, String resolvedType, IBinder whitelistToken,
-            IIntentReceiver finishedReceiver,
-            String requiredPermission, IBinder resultTo, String resultWho, int requestCode,
-            int flagsMask, int flagsValues, Bundle options) {
+            IIntentReceiver finishedReceiver, String requiredPermission, IBinder resultTo,
+            String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle options) {
         if (intent != null) intent.setDefusable(true);
         if (options != null) options.setDefusable(true);
 
-        synchronized (owner) {
-            if (!canceled) {
-                sent = true;
-                if ((key.flags&PendingIntent.FLAG_ONE_SHOT) != 0) {
-                    owner.cancelIntentSenderLocked(this, true);
-                }
+        Long duration = null;
+        Intent finalIntent = null;
+        Intent[] allIntents = null;
+        String[] allResolvedTypes = null;
+        SafeActivityOptions mergedOptions = null;
+        synchronized (controller.mLock) {
+            if (canceled) {
+                return ActivityManager.START_CANCELED;
+            }
 
-                Intent finalIntent = key.requestIntent != null
-                        ? new Intent(key.requestIntent) : new Intent();
+            sent = true;
+            if ((key.flags & PendingIntent.FLAG_ONE_SHOT) != 0) {
+                controller.cancelIntentSender(this, true);
+            }
 
-                final boolean immutable = (key.flags & PendingIntent.FLAG_IMMUTABLE) != 0;
-                if (!immutable) {
-                    if (intent != null) {
-                        int changes = finalIntent.fillIn(intent, key.flags);
-                        if ((changes & Intent.FILL_IN_DATA) == 0) {
-                            resolvedType = key.requestResolvedType;
-                        }
-                    } else {
+            finalIntent = key.requestIntent != null ? new Intent(key.requestIntent) : new Intent();
+
+            final boolean immutable = (key.flags & PendingIntent.FLAG_IMMUTABLE) != 0;
+            if (!immutable) {
+                if (intent != null) {
+                    int changes = finalIntent.fillIn(intent, key.flags);
+                    if ((changes & Intent.FILL_IN_DATA) == 0) {
                         resolvedType = key.requestResolvedType;
                     }
-                    flagsMask &= ~Intent.IMMUTABLE_FLAGS;
-                    flagsValues &= flagsMask;
-                    finalIntent.setFlags((finalIntent.getFlags() & ~flagsMask) | flagsValues);
                 } else {
                     resolvedType = key.requestResolvedType;
                 }
-
-                final int callingUid = Binder.getCallingUid();
-                final int callingPid = Binder.getCallingPid();
-
-                // Extract options before clearing calling identity
-                SafeActivityOptions mergedOptions = key.options;
-                if (mergedOptions == null) {
-                    mergedOptions = SafeActivityOptions.fromBundle(options);
-                } else {
-                    mergedOptions.setCallerOptions(ActivityOptions.fromBundle(options));
-                }
-
-                final long origId = Binder.clearCallingIdentity();
-
-                if (whitelistDuration != null) {
-                    Long duration = whitelistDuration.get(whitelistToken);
-                    if (duration != null) {
-                        int procState = owner.getUidState(callingUid);
-                        if (!ActivityManager.isProcStateBackground(procState)) {
-                            StringBuilder tag = new StringBuilder(64);
-                            tag.append("pendingintent:");
-                            UserHandle.formatUid(tag, callingUid);
-                            tag.append(":");
-                            if (finalIntent.getAction() != null) {
-                                tag.append(finalIntent.getAction());
-                            } else if (finalIntent.getComponent() != null) {
-                                finalIntent.getComponent().appendShortString(tag);
-                            } else if (finalIntent.getData() != null) {
-                                tag.append(finalIntent.getData().toSafeString());
-                            }
-                            owner.tempWhitelistForPendingIntentLocked(callingPid,
-                                    callingUid, uid, duration, tag.toString());
-                        } else {
-                            Slog.w(TAG, "Not doing whitelist " + this + ": caller state="
-                                    + procState);
-                        }
-                    }
-                }
-
-                boolean sendFinish = finishedReceiver != null;
-                int userId = key.userId;
-                if (userId == UserHandle.USER_CURRENT) {
-                    userId = owner.mUserController.getCurrentOrTargetUserId();
-                }
-                int res = START_SUCCESS;
-                switch (key.type) {
-                    case ActivityManager.INTENT_SENDER_ACTIVITY:
-                        try {
-                            // Note when someone has a pending intent, even from different
-                            // users, then there's no need to ensure the calling user matches
-                            // the target user, so validateIncomingUser is always false below.
-
-                            if (key.allIntents != null && key.allIntents.length > 1) {
-                                Intent[] allIntents = new Intent[key.allIntents.length];
-                                String[] allResolvedTypes = new String[key.allIntents.length];
-                                System.arraycopy(key.allIntents, 0, allIntents, 0,
-                                        key.allIntents.length);
-                                if (key.allResolvedTypes != null) {
-                                    System.arraycopy(key.allResolvedTypes, 0, allResolvedTypes, 0,
-                                            key.allResolvedTypes.length);
-                                }
-                                allIntents[allIntents.length-1] = finalIntent;
-                                allResolvedTypes[allResolvedTypes.length-1] = resolvedType;
-
-                                res = owner.mActivityTaskManager.getActivityStartController().startActivitiesInPackage(
-                                        uid, key.packageName, allIntents, allResolvedTypes,
-                                        resultTo, mergedOptions, userId,
-                                        false /* validateIncomingUser */,
-                                        this /* originatingPendingIntent */);
-                            } else {
-                                res = owner.mActivityTaskManager.getActivityStartController().startActivityInPackage(uid,
-                                        callingPid, callingUid, key.packageName, finalIntent,
-                                        resolvedType, resultTo, resultWho, requestCode, 0,
-                                        mergedOptions, userId, null, "PendingIntentRecord",
-                                        false /* validateIncomingUser */,
-                                        this /* originatingPendingIntent */);
-                            }
-                        } catch (RuntimeException e) {
-                            Slog.w(TAG, "Unable to send startActivity intent", e);
-                        }
-                        break;
-                    case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT:
-                        final ActivityStack stack = key.activity.getStack();
-                        if (stack != null) {
-                            stack.sendActivityResultLocked(-1, key.activity, key.who,
-                                    key.requestCode, code, finalIntent);
-                        }
-                        break;
-                    case ActivityManager.INTENT_SENDER_BROADCAST:
-                        try {
-                            // If a completion callback has been requested, require
-                            // that the broadcast be delivered synchronously
-                            int sent = owner.broadcastIntentInPackage(key.packageName, uid,
-                                    finalIntent, resolvedType, finishedReceiver, code, null, null,
-                                    requiredPermission, options, (finishedReceiver != null),
-                                    false, userId);
-                            if (sent == ActivityManager.BROADCAST_SUCCESS) {
-                                sendFinish = false;
-                            }
-                        } catch (RuntimeException e) {
-                            Slog.w(TAG, "Unable to send startActivity intent", e);
-                        }
-                        break;
-                    case ActivityManager.INTENT_SENDER_SERVICE:
-                    case ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE:
-                        try {
-                            owner.startServiceInPackage(uid, finalIntent, resolvedType,
-                                    key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE,
-                                    key.packageName, userId);
-                        } catch (RuntimeException e) {
-                            Slog.w(TAG, "Unable to send startService intent", e);
-                        } catch (TransactionTooLargeException e) {
-                            res = ActivityManager.START_CANCELED;
-                        }
-                        break;
-                }
-
-                if (sendFinish && res != ActivityManager.START_CANCELED) {
-                    try {
-                        finishedReceiver.performReceive(new Intent(finalIntent), 0,
-                                null, null, false, false, key.userId);
-                    } catch (RemoteException e) {
-                    }
-                }
-
-                Binder.restoreCallingIdentity(origId);
-
-                return res;
+                flagsMask &= ~Intent.IMMUTABLE_FLAGS;
+                flagsValues &= flagsMask;
+                finalIntent.setFlags((finalIntent.getFlags() & ~flagsMask) | flagsValues);
+            } else {
+                resolvedType = key.requestResolvedType;
             }
+
+            // Extract options before clearing calling identity
+            mergedOptions = key.options;
+            if (mergedOptions == null) {
+                mergedOptions = SafeActivityOptions.fromBundle(options);
+            } else {
+                mergedOptions.setCallerOptions(ActivityOptions.fromBundle(options));
+            }
+
+            if (whitelistDuration != null) {
+                duration = whitelistDuration.get(whitelistToken);
+            }
+
+            if (key.type == ActivityManager.INTENT_SENDER_ACTIVITY
+                    && key.allIntents != null && key.allIntents.length > 1) {
+                // Copy all intents and resolved types while we have the controller lock so we can
+                // use it later when the lock isn't held.
+                allIntents = new Intent[key.allIntents.length];
+                allResolvedTypes = new String[key.allIntents.length];
+                System.arraycopy(key.allIntents, 0, allIntents, 0, key.allIntents.length);
+                if (key.allResolvedTypes != null) {
+                    System.arraycopy(key.allResolvedTypes, 0, allResolvedTypes, 0,
+                            key.allResolvedTypes.length);
+                }
+                allIntents[allIntents.length - 1] = finalIntent;
+                allResolvedTypes[allResolvedTypes.length - 1] = resolvedType;
+            }
+
         }
-        return ActivityManager.START_CANCELED;
+        // We don't hold the controller lock beyond this point as we will be calling into AM and WM.
+
+        final int callingUid = Binder.getCallingUid();
+        final int callingPid = Binder.getCallingPid();
+        final long origId = Binder.clearCallingIdentity();
+
+        int res = START_SUCCESS;
+        try {
+            if (duration != null) {
+                int procState = controller.mAmInternal.getUidProcessState(callingUid);
+                if (!ActivityManager.isProcStateBackground(procState)) {
+                    StringBuilder tag = new StringBuilder(64);
+                    tag.append("pendingintent:");
+                    UserHandle.formatUid(tag, callingUid);
+                    tag.append(":");
+                    if (finalIntent.getAction() != null) {
+                        tag.append(finalIntent.getAction());
+                    } else if (finalIntent.getComponent() != null) {
+                        finalIntent.getComponent().appendShortString(tag);
+                    } else if (finalIntent.getData() != null) {
+                        tag.append(finalIntent.getData().toSafeString());
+                    }
+                    controller.mAmInternal.tempWhitelistForPendingIntent(callingPid, callingUid,
+                            uid, duration, tag.toString());
+                } else {
+                    Slog.w(TAG, "Not doing whitelist " + this + ": caller state=" + procState);
+                }
+            }
+
+            boolean sendFinish = finishedReceiver != null;
+            int userId = key.userId;
+            if (userId == UserHandle.USER_CURRENT) {
+                userId = controller.mUserController.getCurrentOrTargetUserId();
+            }
+
+            switch (key.type) {
+                case ActivityManager.INTENT_SENDER_ACTIVITY:
+                    try {
+                        // Note when someone has a pending intent, even from different
+                        // users, then there's no need to ensure the calling user matches
+                        // the target user, so validateIncomingUser is always false below.
+
+                        if (key.allIntents != null && key.allIntents.length > 1) {
+                            res = controller.mAtmInternal.startActivitiesInPackage(
+                                    uid, key.packageName, allIntents, allResolvedTypes, resultTo,
+                                    mergedOptions, userId, false /* validateIncomingUser */,
+                                    this /* originatingPendingIntent */);
+                        } else {
+                            res = controller.mAtmInternal.startActivityInPackage(
+                                    uid, callingPid, callingUid, key.packageName, finalIntent,
+                                    resolvedType, resultTo, resultWho, requestCode, 0,
+                                    mergedOptions, userId, null, "PendingIntentRecord",
+                                    false /* validateIncomingUser */,
+                                    this /* originatingPendingIntent */);
+                        }
+                    } catch (RuntimeException e) {
+                        Slog.w(TAG, "Unable to send startActivity intent", e);
+                    }
+                    break;
+                case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT:
+                    controller.mAtmInternal.sendActivityResult(-1, key.activity, key.who,
+                                key.requestCode, code, finalIntent);
+                    break;
+                case ActivityManager.INTENT_SENDER_BROADCAST:
+                    try {
+                        // If a completion callback has been requested, require
+                        // that the broadcast be delivered synchronously
+                        int sent = controller.mAmInternal.broadcastIntentInPackage(key.packageName,
+                                uid, finalIntent, resolvedType, finishedReceiver, code, null, null,
+                                requiredPermission, options, (finishedReceiver != null),
+                                false, userId);
+                        if (sent == ActivityManager.BROADCAST_SUCCESS) {
+                            sendFinish = false;
+                        }
+                    } catch (RuntimeException e) {
+                        Slog.w(TAG, "Unable to send startActivity intent", e);
+                    }
+                    break;
+                case ActivityManager.INTENT_SENDER_SERVICE:
+                case ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE:
+                    try {
+                        controller.mAmInternal.startServiceInPackage(uid, finalIntent, resolvedType,
+                                key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE,
+                                key.packageName, userId);
+                    } catch (RuntimeException e) {
+                        Slog.w(TAG, "Unable to send startService intent", e);
+                    } catch (TransactionTooLargeException e) {
+                        res = ActivityManager.START_CANCELED;
+                    }
+                    break;
+            }
+
+            if (sendFinish && res != ActivityManager.START_CANCELED) {
+                try {
+                    finishedReceiver.performReceive(new Intent(finalIntent), 0,
+                            null, null, false, false, key.userId);
+                } catch (RemoteException e) {
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+
+        return res;
     }
 
     @Override
     protected void finalize() throws Throwable {
         try {
             if (!canceled) {
-                owner.mHandler.sendMessage(owner.mHandler.obtainMessage(
-                        ActivityManagerService.FINALIZE_PENDING_INTENT_MSG, this));
+                controller.mH.sendMessage(PooledLambda.obtainMessage(
+                        PendingIntentRecord::completeFinalize, this));
             }
         } finally {
             super.finalize();
         }
     }
 
-    public void completeFinalize() {
-        synchronized(owner) {
-            WeakReference<PendingIntentRecord> current =
-                    owner.mIntentSenderRecords.get(key);
+    private void completeFinalize() {
+        synchronized(controller.mLock) {
+            WeakReference<PendingIntentRecord> current = controller.mIntentSenderRecords.get(key);
             if (current == ref) {
-                owner.mIntentSenderRecords.remove(key);
+                controller.mIntentSenderRecords.remove(key);
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 784d62e..3ac7885 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -104,6 +104,11 @@
     static final int VISIBLE_APP_ADJ = 100;
     static final int VISIBLE_APP_LAYER_MAX = PERCEPTIBLE_APP_ADJ - VISIBLE_APP_ADJ - 1;
 
+    // This is a process that was recently TOP and moved to FGS. Continue to treat it almost
+    // like a foreground app for a while.
+    // @see TOP_TO_FGS_GRACE_PERIOD
+    static final int PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ = 50;
+
     // This is the process running the current foreground app.  We'd really
     // rather not kill it!
     static final int FOREGROUND_APP_ADJ = 0;
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 144f18b..667d3fa 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -17,18 +17,10 @@
 package com.android.server.am;
 
 import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
+
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 
-import android.os.Debug;
-import android.util.ArraySet;
-import android.util.DebugUtils;
-import android.util.EventLog;
-import android.util.Slog;
-import com.android.internal.app.procstats.ProcessStats;
-import com.android.internal.app.procstats.ProcessState;
-import com.android.internal.os.BatteryStatsImpl;
-
 import android.app.ActivityManager;
 import android.app.Dialog;
 import android.app.IApplicationThread;
@@ -36,7 +28,9 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
 import android.os.Binder;
+import android.os.Debug;
 import android.os.IBinder;
 import android.os.Process;
 import android.os.RemoteException;
@@ -44,10 +38,18 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.DebugUtils;
+import android.util.EventLog;
+import android.util.Slog;
 import android.util.StatsLog;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 
+import com.android.internal.app.procstats.ProcessState;
+import com.android.internal.app.procstats.ProcessStats;
+import com.android.internal.os.BatteryStatsImpl;
+
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -198,6 +200,7 @@
     long lastRequestedGc;       // When we last asked the app to do a gc
     long lastLowMemory;         // When we last told the app that memory is low
     long lastProviderTime;      // The last time someone else was using a provider in this process.
+    long lastTopTime;           // The last time the process was in the TOP state or greater.
     boolean reportLowMemory;    // Set to true when waiting to report low mem
     boolean empty;              // Is this an empty background process?
     boolean cached;             // Is this a cached process?
@@ -306,6 +309,7 @@
             pw.print(prefix); pw.print("manageSpaceActivityName=");
             pw.println(info.manageSpaceActivityName);
         }
+
         pw.print(prefix); pw.print("dir="); pw.print(info.sourceDir);
                 pw.print(" publicDir="); pw.print(info.publicSourceDir);
                 pw.print(" data="); pw.println(info.dataDir);
@@ -415,6 +419,11 @@
             TimeUtils.formatDuration(lastProviderTime, nowUptime, pw);
             pw.println();
         }
+        if (lastTopTime > 0) {
+            pw.print(prefix); pw.print("lastTopTime=");
+            TimeUtils.formatDuration(lastTopTime, nowUptime, pw);
+            pw.println();
+        }
         if (hasStartedServices) {
             pw.print(prefix); pw.print("hasStartedServices="); pw.println(hasStartedServices);
         }
@@ -514,7 +523,7 @@
     }
 
     ProcessRecord(ActivityManagerService _service, ApplicationInfo _info, String _processName,
-            int _uid) {
+            int _uid, Configuration config) {
         mService = _service;
         info = _info;
         isolated = _info.uid != _uid;
@@ -528,7 +537,7 @@
         removed = false;
         lastStateTime = lastPssTime = nextPssTime = SystemClock.uptimeMillis();
         mWindowProcessController = new WindowProcessController(
-                mService.mActivityTaskManager, info, processName, uid, userId, this, this);
+                mService.mActivityTaskManager, info, processName, uid, userId, this, this, config);
         pkgList.put(_info.packageName, new ProcessStats.ProcessStateHolder(_info.longVersionCode));
     }
 
diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java
index 8ce650c..6ffd8a9 100644
--- a/services/core/java/com/android/server/am/ProcessStatsService.java
+++ b/services/core/java/com/android/server/am/ProcessStatsService.java
@@ -23,8 +23,10 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.service.procstats.ProcessStatsServiceDumpProto;
+import android.text.format.DateFormat;
 import android.util.ArrayMap;
 import android.util.AtomicFile;
+import android.util.Log;
 import android.util.LongSparseArray;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -47,6 +49,7 @@
 import java.io.InputStream;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.locks.ReentrantLock;
@@ -482,6 +485,23 @@
         return finalRes;
     }
 
+    static int parseSectionOptions(String optionsStr) {
+        final String sep = ",";
+        String[] sectionsStr = optionsStr.split(sep);
+        if (sectionsStr.length == 0) {
+            return ProcessStats.REPORT_ALL;
+        }
+        int res = 0;
+        List<String> optionStrList = Arrays.asList(ProcessStats.OPTIONS_STR);
+        for (String sectionStr : sectionsStr) {
+            int optionIndex = optionStrList.indexOf(sectionStr);
+            if (optionIndex != -1) {
+                res |= ProcessStats.OPTIONS[optionIndex];
+            }
+        }
+        return res;
+    }
+
     public byte[] getCurrentStats(List<ParcelFileDescriptor> historic) {
         mAm.mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.PACKAGE_USAGE_STATS, null);
@@ -514,6 +534,95 @@
         return current.marshall();
     }
 
+    /**
+     * Get stats committed after highWaterMarkMs
+     * @param highWaterMarkMs Report stats committed after this time.
+     * @param section Integer mask to indicage which sections to include in the stats.
+     * @param doAggregate Whether to aggregate the stats or keep them separated.
+     * @return List of proto binary of individual commit files or one that is merged from them.
+     */
+    @Override
+    public long getCommittedStats(long highWaterMarkMs, int section, boolean doAggregate,
+            List<ParcelFileDescriptor> committedStats) {
+        mAm.mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.PACKAGE_USAGE_STATS, null);
+
+        ProcessStats mergedStats = new ProcessStats(false);
+        long newHighWaterMark = highWaterMarkMs;
+        mWriteLock.lock();
+        try {
+            ArrayList<String> files = getCommittedFiles(0, false, true);
+            if (files != null) {
+                String highWaterMarkStr =
+                        DateFormat.format("yyyy-MM-dd-HH-mm-ss", highWaterMarkMs).toString();
+                ProcessStats stats = new ProcessStats(false);
+                for (int i = files.size() - 1; i >= 0; i--) {
+                    String fileName = files.get(i);
+                    try {
+                        String startTimeStr = fileName.substring(
+                                fileName.lastIndexOf(STATE_FILE_PREFIX)
+                                        + STATE_FILE_PREFIX.length(),
+                                fileName.lastIndexOf(STATE_FILE_SUFFIX));
+                        if (startTimeStr.compareToIgnoreCase(highWaterMarkStr) > 0) {
+                            ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
+                                    new File(fileName),
+                                    ParcelFileDescriptor.MODE_READ_ONLY);
+                            InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+                            stats.reset();
+                            stats.read(is);
+                            is.close();
+                            if (stats.mTimePeriodStartClock > newHighWaterMark) {
+                                newHighWaterMark = stats.mTimePeriodStartClock;
+                            }
+                            if (doAggregate) {
+                                mergedStats.add(stats);
+                            } else {
+                                committedStats.add(protoToParcelFileDescriptor(stats, section));
+                            }
+                            if (stats.mReadError != null) {
+                                Log.w(TAG, "Failure reading process stats: " + stats.mReadError);
+                                continue;
+                            }
+                        }
+                    } catch (IOException e) {
+                        Slog.w(TAG, "Failure opening procstat file " + fileName, e);
+                    } catch (IndexOutOfBoundsException e) {
+                        Slog.w(TAG, "Failure to read and parse commit file " + fileName, e);
+                    }
+                }
+                if (doAggregate) {
+                    committedStats.add(protoToParcelFileDescriptor(mergedStats, section));
+                }
+                return newHighWaterMark;
+            }
+        } catch (IOException e) {
+            Slog.w(TAG, "Failure opening procstat file", e);
+        } finally {
+            mWriteLock.unlock();
+        }
+        return newHighWaterMark;
+    }
+
+    private ParcelFileDescriptor protoToParcelFileDescriptor(ProcessStats stats, int section)
+            throws IOException {
+        final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
+        Thread thr = new Thread("ProcessStats pipe output") {
+            public void run() {
+                try {
+                    FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream(fds[1]);
+                    final ProtoOutputStream proto = new ProtoOutputStream(fout);
+                    stats.writeToProto(proto, stats.mTimePeriodEndRealtime, section);
+                    proto.flush();
+                    fout.close();
+                } catch (IOException e) {
+                    Slog.w(TAG, "Failure writing pipe", e);
+                }
+            }
+        };
+        thr.start();
+        return fds[0];
+    }
+
     public ParcelFileDescriptor getStatsOverTime(long minTime) {
         mAm.mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.PACKAGE_USAGE_STATS, null);
@@ -594,7 +703,7 @@
 
     private void dumpAggregatedStats(PrintWriter pw, long aggregateHours, long now,
             String reqPackage, boolean isCompact, boolean dumpDetails, boolean dumpFullDetails,
-            boolean dumpAll, boolean activeOnly) {
+            boolean dumpAll, boolean activeOnly, int section) {
         ParcelFileDescriptor pfd = getStatsOverTime(aggregateHours*60*60*1000
                 - (ProcessStats.COMMIT_PERIOD/2));
         if (pfd == null) {
@@ -609,11 +718,11 @@
             return;
         }
         if (isCompact) {
-            stats.dumpCheckinLocked(pw, reqPackage);
+            stats.dumpCheckinLocked(pw, reqPackage, section);
         } else {
             if (dumpDetails || dumpFullDetails) {
                 stats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails, dumpAll,
-                        activeOnly);
+                        activeOnly, section);
             } else {
                 stats.dumpSummaryLocked(pw, reqPackage, now, activeOnly);
             }
@@ -643,6 +752,8 @@
         pw.println("  --max: for -a, max num of historical batches to print.");
         pw.println("  --active: only show currently active processes/services.");
         pw.println("  --commit: commit current stats to disk and reset to start new stats.");
+        pw.println("  --section: proc|pkg-proc|pkg-svc|pkg-asc|pkg-all|all ");
+        pw.println("    options can be combined to select desired stats");
         pw.println("  --reset: reset current stats, without committing.");
         pw.println("  --clear: clear all stats; does both --reset and deletes old stats.");
         pw.println("  --write: write current in-memory stats to disk.");
@@ -696,6 +807,7 @@
         int[] csvMemStats = new int[] { ProcessStats.ADJ_MEM_FACTOR_CRITICAL};
         boolean csvSepProcStats = true;
         int[] csvProcStats = ProcessStats.ALL_PROC_STATES;
+        int section = ProcessStats.REPORT_ALL;
         if (args != null) {
             for (int i=0; i<args.length; i++) {
                 String arg = args[i];
@@ -814,13 +926,14 @@
                         pw.println("Process stats committed.");
                         quit = true;
                     }
-                } else if ("--reset".equals(arg)) {
-                    synchronized (mAm) {
-                        mProcessStats.resetSafely();
-                        mAm.requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
-                        pw.println("Process stats reset.");
-                        quit = true;
+                } else if ("--section".equals(arg)) {
+                    i++;
+                    if (i >= args.length) {
+                        pw.println("Error: argument required for --section");
+                        dumpHelp(pw);
+                        return;
                     }
+                    section = parseSectionOptions(args[i]);
                 } else if ("--clear".equals(arg)) {
                     synchronized (mAm) {
                         mProcessStats.resetSafely();
@@ -946,7 +1059,7 @@
         } else if (aggregateHours != 0) {
             pw.print("AGGREGATED OVER LAST "); pw.print(aggregateHours); pw.println(" HOURS:");
             dumpAggregatedStats(pw, aggregateHours, now, reqPackage, isCompact,
-                    dumpDetails, dumpFullDetails, dumpAll, activeOnly);
+                    dumpDetails, dumpFullDetails, dumpAll, activeOnly, section);
             return;
         } else if (lastIndex > 0) {
             pw.print("LAST STATS AT INDEX "); pw.print(lastIndex); pw.println(":");
@@ -968,7 +1081,7 @@
             boolean checkedIn = fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX);
             if (isCheckin || isCompact) {
                 // Don't really need to lock because we uniquely own this object.
-                processStats.dumpCheckinLocked(pw, reqPackage);
+                processStats.dumpCheckinLocked(pw, reqPackage, section);
             } else {
                 pw.print("COMMITTED STATS FROM ");
                 pw.print(processStats.mTimePeriodStartClockStr);
@@ -976,7 +1089,7 @@
                 pw.println(":");
                 if (dumpDetails || dumpFullDetails) {
                     processStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails,
-                            dumpAll, activeOnly);
+                            dumpAll, activeOnly, section);
                     if (dumpAll) {
                         pw.print("  mFile="); pw.println(mFile.getBaseFile());
                     }
@@ -1015,7 +1128,7 @@
                             boolean checkedIn = fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX);
                             if (isCheckin || isCompact) {
                                 // Don't really need to lock because we uniquely own this object.
-                                processStats.dumpCheckinLocked(pw, reqPackage);
+                                processStats.dumpCheckinLocked(pw, reqPackage, section);
                             } else {
                                 if (sepNeeded) {
                                     pw.println();
@@ -1031,7 +1144,7 @@
                                 // much crud.
                                 if (dumpFullDetails) {
                                     processStats.dumpLocked(pw, reqPackage, now, false, false,
-                                            false, activeOnly);
+                                            false, activeOnly, section);
                                 } else {
                                     processStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly);
                                 }
@@ -1054,7 +1167,7 @@
         if (!isCheckin) {
             synchronized (mAm) {
                 if (isCompact) {
-                    mProcessStats.dumpCheckinLocked(pw, reqPackage);
+                    mProcessStats.dumpCheckinLocked(pw, reqPackage, section);
                 } else {
                     if (sepNeeded) {
                         pw.println();
@@ -1062,7 +1175,7 @@
                     pw.println("CURRENT STATS:");
                     if (dumpDetails || dumpFullDetails) {
                         mProcessStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails,
-                                dumpAll, activeOnly);
+                                dumpAll, activeOnly, section);
                         if (dumpAll) {
                             pw.print("  mFile="); pw.println(mFile.getBaseFile());
                         }
@@ -1078,11 +1191,11 @@
                 }
                 pw.println("AGGREGATED OVER LAST 24 HOURS:");
                 dumpAggregatedStats(pw, 24, now, reqPackage, isCompact,
-                        dumpDetails, dumpFullDetails, dumpAll, activeOnly);
+                        dumpDetails, dumpFullDetails, dumpAll, activeOnly, section);
                 pw.println();
                 pw.println("AGGREGATED OVER LAST 3 HOURS:");
                 dumpAggregatedStats(pw, 3, now, reqPackage, isCompact,
-                        dumpDetails, dumpFullDetails, dumpAll, activeOnly);
+                        dumpDetails, dumpFullDetails, dumpAll, activeOnly, section);
             }
         }
     }
@@ -1099,7 +1212,9 @@
         if (stats.mReadError != null) {
             return;
         }
-        stats.writeToProto(proto, fieldId, now);
+        final long token = proto.start(fieldId);
+        stats.writeToProto(proto, now, ProcessStats.REPORT_ALL);
+        proto.end(token);
     }
 
     private void dumpProto(FileDescriptor fd) {
@@ -1109,7 +1224,9 @@
         long now;
         synchronized (mAm) {
             now = SystemClock.uptimeMillis();
-            mProcessStats.writeToProto(proto,ProcessStatsServiceDumpProto.PROCSTATS_NOW, now);
+            final long token = proto.start(ProcessStatsServiceDumpProto.PROCSTATS_NOW);
+            mProcessStats.writeToProto(proto, now, ProcessStats.REPORT_ALL);
+            proto.end(token);
         }
 
         // aggregated over last 3 hours procstats
diff --git a/services/core/java/com/android/server/am/SafeActivityOptions.java b/services/core/java/com/android/server/am/SafeActivityOptions.java
index f7de7f4..fa0cb47 100644
--- a/services/core/java/com/android/server/am/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/am/SafeActivityOptions.java
@@ -44,7 +44,7 @@
  * the inner options. Also supports having two set of options: Once from the original caller, and
  * once from the caller that is overriding it, which happens when sending a {@link PendingIntent}.
  */
-class SafeActivityOptions {
+public class SafeActivityOptions {
 
     private static final String TAG = TAG_WITH_CLASS_NAME ? "SafeActivityOptions" : TAG_AM;
 
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 7256e23..ef8cb1c 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -129,7 +129,8 @@
 import java.util.ArrayList;
 import java.util.Objects;
 
-class TaskRecord extends ConfigurationContainer implements TaskWindowContainerListener {
+// TODO: Make package private again once move to WM package is complete.
+public class TaskRecord extends ConfigurationContainer implements TaskWindowContainerListener {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM;
     private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
     private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
@@ -1521,14 +1522,14 @@
 
     /**
      * Check whether this task can be launched on the specified display.
+     *
      * @param displayId Target display id.
-     * @return {@code true} if either it is the default display or this activity is resizeable and
-     *         can be put a secondary screen.
+     * @return {@code true} if either it is the default display or this activity can be put on a
+     *         secondary display.
      */
     boolean canBeLaunchedOnDisplay(int displayId) {
         return mService.mStackSupervisor.canPlaceEntityOnDisplay(displayId,
-                isResizeable(false /* checkSupportsPip */), -1 /* don't check PID */,
-                -1 /* don't check UID */, null /* activityInfo */);
+                -1 /* don't check PID */, -1 /* don't check UID */, null /* activityInfo */);
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index bd412fc..8154062 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -850,10 +850,16 @@
     }
 
     void scheduleStartProfiles() {
-        if (!mHandler.hasMessages(START_PROFILES_MSG)) {
-            mHandler.sendMessageDelayed(mHandler.obtainMessage(START_PROFILES_MSG),
-                    DateUtils.SECOND_IN_MILLIS);
-        }
+        // Parent user transition to RUNNING_UNLOCKING happens on FgThread, so it is busy, there is
+        // a chance the profile will reach RUNNING_LOCKED while parent is still locked, so no
+        // attempt will be made to unlock the profile. If we go via FgThread, this will be executed
+        // after the parent had chance to unlock fully.
+        FgThread.getHandler().post(() -> {
+            if (!mHandler.hasMessages(START_PROFILES_MSG)) {
+                mHandler.sendMessageDelayed(mHandler.obtainMessage(START_PROFILES_MSG),
+                        DateUtils.SECOND_IN_MILLIS);
+            }
+        });
     }
 
     void startProfiles() {
diff --git a/services/core/java/com/android/server/am/WindowProcessController.java b/services/core/java/com/android/server/am/WindowProcessController.java
index e5551b5..f6f4db6 100644
--- a/services/core/java/com/android/server/am/WindowProcessController.java
+++ b/services/core/java/com/android/server/am/WindowProcessController.java
@@ -17,7 +17,10 @@
 package com.android.server.am;
 
 import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
+
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RELEASE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RELEASE;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -29,11 +32,13 @@
 import static com.android.server.am.ActivityStack.ActivityState.STOPPING;
 
 import android.app.Activity;
-import android.app.ActivityTaskManager;
 import android.app.ActivityThread;
 import android.app.IApplicationThread;
+import android.app.servertransaction.ConfigurationChangeItem;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
+import android.content.res.Configuration;
+import android.os.Message;
 import android.os.RemoteException;
 import android.util.ArraySet;
 import android.util.Log;
@@ -41,7 +46,7 @@
 
 import com.android.internal.app.HeavyWeightSwitcherActivity;
 import com.android.internal.util.function.pooled.PooledLambda;
-import com.android.internal.util.function.pooled.PooledRunnable;
+import com.android.server.wm.ConfigurationContainer;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -57,9 +62,10 @@
  * window manager so the window manager lock is held and appropriate permissions are checked before
  * calls are allowed to proceed.
  */
-public class WindowProcessController {
+public class WindowProcessController extends ConfigurationContainer<ConfigurationContainer> {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowProcessController" : TAG_AM;
     private static final String TAG_RELEASE = TAG + POSTFIX_RELEASE;
+    private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
 
     // all about the first app in the process
     final ApplicationInfo mInfo;
@@ -108,8 +114,12 @@
     // any tasks this process had run root activities in
     private final ArrayList<TaskRecord> mRecentTasks = new ArrayList<>();
 
+    // Last configuration that was reported to the process.
+    private final Configuration mLastReportedConfiguration;
+
     WindowProcessController(ActivityTaskManagerService atm, ApplicationInfo info, String name,
-            int uid, int userId, Object owner, WindowProcessListener listener) {
+            int uid, int userId, Object owner, WindowProcessListener listener,
+            Configuration config) {
         mInfo = info;
         mName = name;
         mUid = uid;
@@ -117,6 +127,10 @@
         mOwner = owner;
         mListener = listener;
         mAtm = atm;
+        mLastReportedConfiguration = new Configuration();
+        if (config != null) {
+            onConfigurationChanged(config);
+        }
     }
 
     public void setPid(int pid) {
@@ -219,6 +233,21 @@
         return mInstrumenting;
     }
 
+    @Override
+    protected int getChildCount() {
+        return 0;
+    }
+
+    @Override
+    protected ConfigurationContainer getChildAt(int index) {
+        return null;
+    }
+
+    @Override
+    protected ConfigurationContainer getParent() {
+        return null;
+    }
+
     public void addPackage(String packageName) {
         synchronized (mAtm.mGlobalLock) {
             mPkgList.add(packageName);
@@ -482,48 +511,94 @@
     void clearProfilerIfNeeded() {
         if (mListener == null) return;
         // Posting on handler so WM lock isn't held when we call into AM.
-        mAtm.mH.post(() -> mListener.clearProfilerIfNeeded());
+        mAtm.mH.sendMessage(PooledLambda.obtainMessage(
+                WindowProcessListener::clearProfilerIfNeeded, mListener));
     }
 
     void updateProcessInfo(boolean updateServiceConnectionActivities, boolean updateLru,
             boolean activityChange, boolean updateOomAdj) {
         if (mListener == null) return;
         // Posting on handler so WM lock isn't held when we call into AM.
-        final Runnable r = PooledLambda.obtainRunnable(WindowProcessListener::updateProcessInfo,
+        final Message m = PooledLambda.obtainMessage(WindowProcessListener::updateProcessInfo,
                 mListener, updateServiceConnectionActivities, updateLru, activityChange,
                 updateOomAdj);
-        mAtm.mH.post(r);
+        mAtm.mH.sendMessage(m);
     }
 
     void updateServiceConnectionActivities() {
         if (mListener == null) return;
         // Posting on handler so WM lock isn't held when we call into AM.
-        mAtm.mH.post(() -> mListener.updateServiceConnectionActivities());
+        mAtm.mH.sendMessage(PooledLambda.obtainMessage(
+                WindowProcessListener::updateServiceConnectionActivities, mListener));
     }
 
     void setPendingUiClean(boolean pendingUiClean) {
         if (mListener == null) return;
         // Posting on handler so WM lock isn't held when we call into AM.
-        final Runnable r = PooledLambda.obtainRunnable(
+        final Message m = PooledLambda.obtainMessage(
                 WindowProcessListener::setPendingUiClean, mListener, pendingUiClean);
-        mAtm.mH.post(r);
+        mAtm.mH.sendMessage(m);
     }
 
     void setPendingUiCleanAndForceProcessStateUpTo(int newState) {
         if (mListener == null) return;
         // Posting on handler so WM lock isn't held when we call into AM.
-        final Runnable r = PooledLambda.obtainRunnable(
+        final Message m = PooledLambda.obtainMessage(
                 WindowProcessListener::setPendingUiCleanAndForceProcessStateUpTo,
                 mListener, newState);
-        mAtm.mH.post(r);
+        mAtm.mH.sendMessage(m);
     }
 
     void setRemoved(boolean removed) {
         if (mListener == null) return;
         // Posting on handler so WM lock isn't held when we call into AM.
-        final Runnable r = PooledLambda.obtainRunnable(
+        final Message m = PooledLambda.obtainMessage(
                 WindowProcessListener::setRemoved, mListener, removed);
-        mAtm.mH.post(r);
+        mAtm.mH.sendMessage(m);
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newGlobalConfig) {
+        super.onConfigurationChanged(newGlobalConfig);
+        updateConfiguration();
+    }
+
+    @Override
+    public void onOverrideConfigurationChanged(Configuration newOverrideConfig) {
+        super.onOverrideConfigurationChanged(newOverrideConfig);
+        updateConfiguration();
+    }
+
+    private void updateConfiguration() {
+        final Configuration config = getConfiguration();
+        if (mLastReportedConfiguration.diff(config) == 0) {
+            // Nothing changed.
+            return;
+        }
+
+        try {
+            if (mThread == null) {
+                return;
+            }
+            if (DEBUG_CONFIGURATION) {
+                Slog.v(TAG_CONFIGURATION, "Sending to proc " + mName
+                        + " new config " + config);
+            }
+            config.seq = mAtm.increaseConfigurationSeqLocked();
+            mAtm.getLifecycleManager().scheduleTransaction(mThread,
+                    ConfigurationChangeItem.obtain(config));
+            setLastReportedConfiguration(config);
+        } catch (Exception e) {
+            Slog.e(TAG_CONFIGURATION, "Failed to schedule configuration change", e);
+        }
+    }
+
+    private void setLastReportedConfiguration(Configuration config) {
+        mLastReportedConfiguration.setTo(config);
+    }
+
+    Configuration getLastReportedConfiguration() {
+        return mLastReportedConfiguration;
     }
 
     /** Returns the total time (in milliseconds) spent executing in both user and system code. */
@@ -574,6 +649,9 @@
                 pw.print(prefix); pw.print("mVrThreadTid="); pw.println(mVrThreadTid);
             }
         }
+        pw.println(prefix + " Configuration=" + getConfiguration());
+        pw.println(prefix + " OverrideConfiguration=" + getOverrideConfiguration());
+        pw.println(prefix + " mLastReportedConfiguration=" + mLastReportedConfiguration);
     }
 
 }
diff --git a/services/core/java/com/android/server/appbinding/AppBindingService.java b/services/core/java/com/android/server/appbinding/AppBindingService.java
new file mode 100644
index 0000000..91b3b21
--- /dev/null
+++ b/services/core/java/com/android/server/appbinding/AppBindingService.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.appbinding;
+
+import android.app.AppGlobals;
+import android.content.Context;
+import android.content.pm.IPackageManager;
+import android.os.Binder;
+import android.os.Handler;
+
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.DumpUtils;
+import com.android.server.SystemService;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * System server that keeps a binding to an app to keep it always running.
+ */
+public class AppBindingService extends Binder {
+    public static final String TAG = "AppBindingService";
+
+    private static final boolean DEBUG = false;
+
+    private final Object mLock = new Object();
+
+    private final Injector mInjector;
+    private final Context mContext;
+    private final Handler mHandler;
+    private final IPackageManager mIPackageManager;
+
+    static class Injector {
+        public IPackageManager getIPackageManager() {
+            return AppGlobals.getPackageManager();
+        }
+    }
+
+    /**
+     * System service interacts with this service via this class.
+     */
+    public static final class Lifecycle extends SystemService {
+        final AppBindingService mService;
+
+        public Lifecycle(Context context) {
+            super(context);
+            mService = new AppBindingService(new Injector(), context);
+        }
+
+        @Override
+        public void onStart() {
+            publishBinderService(Context.APP_BINDING_SERVICE, mService);
+        }
+    }
+
+    private AppBindingService(Injector injector, Context context) {
+        mInjector = injector;
+        mContext = context;
+        mIPackageManager = injector.getIPackageManager();
+        mHandler = BackgroundThread.getHandler();
+    }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+    }
+}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 8caa702..66c7c43 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -627,6 +627,13 @@
     // If absolute volume is supported in AVRCP device
     private boolean mAvrcpAbsVolSupported = false;
 
+    // Pre-scale for Bluetooth Absolute Volume
+    private float[] mPrescaleAbsoluteVolume = new float[] {
+        0.5f,    // Pre-scale for index 1
+        0.7f,    // Pre-scale for index 2
+        0.85f,   // Pre-scale for index 3
+    };
+
     private static Long mLastDeviceConnectMsgTime = new Long(0);
 
     private NotificationManager mNm;
@@ -878,6 +885,23 @@
         mUserManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener);
 
         mRecordMonitor.initMonitor();
+
+        final float[] preScale = new float[3];
+        preScale[0] = mContext.getResources().getFraction(
+                com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index1,
+                1, 1);
+        preScale[1] = mContext.getResources().getFraction(
+                com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index2,
+                1, 1);
+        preScale[2] = mContext.getResources().getFraction(
+                com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index3,
+                1, 1);
+        for (int i = 0; i < preScale.length; i++) {
+            if (0.0f <= preScale[i] && preScale[i] <= 1.0f) {
+                mPrescaleAbsoluteVolume[i] = preScale[i];
+            }
+        }
+
     }
 
     public void systemReady() {
@@ -4926,18 +4950,12 @@
             if (index == 0) {
                 // 0% for volume 0
                 index = 0;
-            } else if (index == 1) {
-                // 50% for volume 1
-                index = (int)(mIndexMax * 0.5) /10;
-            } else if (index == 2) {
-                // 70% for volume 2
-                index = (int)(mIndexMax * 0.70) /10;
-            } else if (index == 3) {
-                // 85% for volume 3
-                index = (int)(mIndexMax * 0.85) /10;
+            } else if (index > 0 && index <= 3) {
+                // Pre-scale for volume steps 1 2 and 3
+                index = (int) (mIndexMax * mPrescaleAbsoluteVolume[index - 1]) / 10;
             } else {
                 // otherwise, full gain
-                index = (mIndexMax + 5)/10;
+                index = (mIndexMax + 5) / 10;
             }
             return index;
         }
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
index 36e7cba..aa4d34e 100644
--- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
@@ -26,10 +26,13 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
+import android.security.KeyStore;
 import android.util.Slog;
 
 import com.android.internal.statusbar.IStatusBarService;
 
+import java.util.ArrayList;
+
 /**
  * A class to keep track of the authentication state for a given client.
  */
@@ -39,34 +42,79 @@
 
     public abstract int handleFailedAttempt();
     public abstract void resetFailedAttempts();
+    public abstract String getErrorString(int error, int vendorCode);
+    public abstract String getAcquiredString(int acquireInfo, int vendorCode);
+    /**
+      * @return one of {@link #TYPE_FINGERPRINT} {@link #TYPE_IRIS} or {@link #TYPE_FACE}
+      */
+    public abstract int getBiometricType();
 
     public static final int LOCKOUT_NONE = 0;
     public static final int LOCKOUT_TIMED = 1;
     public static final int LOCKOUT_PERMANENT = 2;
 
-    private final BiometricAuthenticator mAuthenticator;
+    private final boolean mRequireConfirmation;
     // Callback mechanism received from the client
     // (BiometricPrompt -> BiometricPromptService -> <Biometric>Service -> AuthenticationClient)
     private IBiometricPromptReceiver mDialogReceiverFromClient;
     private Bundle mBundle;
     private IStatusBarService mStatusBarService;
     private boolean mInLockout;
+    private TokenEscrow mEscrow;
     protected boolean mDialogDismissed;
 
+    /**
+     * Container that holds the identifier and authToken. For biometrics that require user
+     * confirmation, these should not be sent to their final destinations until the user confirms.
+     */
+    class TokenEscrow {
+        final BiometricAuthenticator.Identifier mIdentifier;
+        final ArrayList<Byte> mToken;
+
+        TokenEscrow(BiometricAuthenticator.Identifier identifier, ArrayList<Byte> token) {
+            mIdentifier = identifier;
+            mToken = token;
+        }
+
+        BiometricAuthenticator.Identifier getIdentifier() {
+            return mIdentifier;
+        }
+
+        ArrayList<Byte> getToken() {
+            return mToken;
+        }
+    }
+
     // Receives events from SystemUI and handles them before forwarding them to BiometricDialog
     protected IBiometricPromptReceiver mDialogReceiver = new IBiometricPromptReceiver.Stub() {
         @Override // binder call
         public void onDialogDismissed(int reason) {
             if (mBundle != null && mDialogReceiverFromClient != null) {
                 try {
-                    mDialogReceiverFromClient.onDialogDismissed(reason);
+                    if (reason != BiometricPrompt.DISMISSED_REASON_POSITIVE) {
+                        // Positive button is used by passive modalities as a "confirm" button,
+                        // do not send to client
+                        mDialogReceiverFromClient.onDialogDismissed(reason);
+                    }
                     if (reason == BiometricPrompt.DISMISSED_REASON_USER_CANCEL) {
                         onError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED,
                                 0 /* vendorCode */);
+                    } else if (reason == BiometricPrompt.DISMISSED_REASON_POSITIVE) {
+                        // Have the service send the token to KeyStore, and send onAuthenticated
+                        // to the application.
+                        if (mEscrow != null) {
+                            if (DEBUG) Slog.d(getLogTag(), "Confirmed");
+                            addTokenToKeyStore(mEscrow.getToken());
+                            notifyClientAuthenticationSucceeded(mEscrow.getIdentifier());
+                            mEscrow = null;
+                            onAuthenticationConfirmed();
+                        } else {
+                            Slog.e(getLogTag(), "Escrow is null!!!");
+                        }
                     }
                     mDialogDismissed = true;
                 } catch (RemoteException e) {
-                    Slog.e(getLogTag(), "Unable to notify dialog dismissed", e);
+                    Slog.e(getLogTag(), "Remote exception", e);
                 }
                 stop(true /* initiatedByClient */);
             }
@@ -84,20 +132,26 @@
      */
     public abstract void onStop();
 
+    /**
+     * This method is called when biometric authentication was confirmed by the user. The client
+     * should be removed.
+     */
+    public abstract void onAuthenticationConfirmed();
+
     public AuthenticationClient(Context context, Metrics metrics,
-            BiometricService.DaemonWrapper daemon, long halDeviceId, IBinder token,
-            BiometricService.ServiceListener listener, int targetUserId, int groupId, long opId,
+            BiometricServiceBase.DaemonWrapper daemon, long halDeviceId, IBinder token,
+            BiometricServiceBase.ServiceListener listener, int targetUserId, int groupId, long opId,
             boolean restricted, String owner, Bundle bundle,
             IBiometricPromptReceiver dialogReceiver, IStatusBarService statusBarService,
-            BiometricAuthenticator authenticator) {
+            boolean requireConfirmation) {
         super(context, metrics, daemon, halDeviceId, token, listener, targetUserId, groupId,
                 restricted, owner);
         mOpId = opId;
         mBundle = bundle;
         mDialogReceiverFromClient = dialogReceiver;
         mStatusBarService = statusBarService;
-        mAuthenticator = authenticator;
         mHandler = new Handler(Looper.getMainLooper());
+        mRequireConfirmation = requireConfirmation;
     }
 
     @Override
@@ -115,8 +169,7 @@
         if (mBundle != null) {
             try {
                 if (acquiredInfo != BiometricConstants.BIOMETRIC_ACQUIRED_GOOD) {
-                    mStatusBarService.onBiometricHelp(
-                            mAuthenticator.getAcquiredString(acquiredInfo, vendorCode));
+                    mStatusBarService.onBiometricHelp(getAcquiredString(acquiredInfo, vendorCode));
                 }
                 return false; // acquisition continues
             } catch (RemoteException e) {
@@ -144,8 +197,7 @@
         }
         if (mBundle != null) {
             try {
-                mStatusBarService.onBiometricError(
-                        mAuthenticator.getErrorString(error, vendorCode));
+                mStatusBarService.onBiometricError(getErrorString(error, vendorCode));
             } catch (RemoteException e) {
                 Slog.e(getLogTag(), "Remote exception when sending error", e);
             }
@@ -153,9 +205,41 @@
         return super.onError(deviceId, error, vendorCode);
     }
 
+    private void notifyClientAuthenticationSucceeded(BiometricAuthenticator.Identifier identifier)
+            throws RemoteException {
+        final BiometricServiceBase.ServiceListener listener = getListener();
+        // Explicitly have if/else here to make it super obvious in case the code is
+        // touched in the future.
+        if (!getIsRestricted()) {
+            listener.onAuthenticationSucceeded(
+                    getHalDeviceId(), identifier, getTargetUserId());
+        } else {
+            listener.onAuthenticationSucceeded(
+                    getHalDeviceId(), null, getTargetUserId());
+        }
+    }
+
+    private void addTokenToKeyStore(ArrayList<Byte> token) {
+        // Send the token to KeyStore
+        final byte[] byteToken = new byte[token.size()];
+        for (int i = 0; i < token.size(); i++) {
+            byteToken[i] = token.get(i);
+        }
+        KeyStore.getInstance().addAuthToken(byteToken);
+    }
+
     @Override
     public boolean onAuthenticated(BiometricAuthenticator.Identifier identifier,
-            boolean authenticated) {
+            boolean authenticated, ArrayList<Byte> token) {
+        if (authenticated) {
+            if (mRequireConfirmation) {
+                // Store the token so it can be sent to keystore after the user presses confirm
+                mEscrow = new TokenEscrow(identifier, token);
+            } else {
+                addTokenToKeyStore(token);
+            }
+        }
+
         boolean result = false;
 
         // If the biometric dialog is showing, notify authentication succeeded
@@ -172,7 +256,7 @@
             }
         }
 
-        final BiometricService.ServiceListener listener = getListener();
+        final BiometricServiceBase.ServiceListener listener = getListener();
         if (listener != null) {
             try {
                 mMetricsLogger.action(mMetrics.actionBiometricAuth(), authenticated);
@@ -183,15 +267,8 @@
                         Slog.v(getLogTag(), "onAuthenticated(owner=" + getOwnerString()
                                 + ", id=" + identifier.getBiometricId());
                     }
-
-                    // Explicitly have if/else here to make it super obvious in case the code is
-                    // touched in the future.
-                    if (!getIsRestricted()) {
-                        listener.onAuthenticationSucceeded(
-                                getHalDeviceId(), identifier, getTargetUserId());
-                    } else {
-                        listener.onAuthenticationSucceeded(
-                                getHalDeviceId(), null, getTargetUserId());
+                    if (!mRequireConfirmation) {
+                        notifyClientAuthenticationSucceeded(identifier);
                     }
                 }
             } catch (RemoteException e) {
@@ -220,7 +297,7 @@
                     // Send the lockout message to the system dialog
                     if (mBundle != null) {
                         mStatusBarService.onBiometricError(
-                                mAuthenticator.getErrorString(errorCode, 0 /* vendorCode */));
+                                getErrorString(errorCode, 0 /* vendorCode */));
                         mHandler.postDelayed(() -> {
                             try {
                                 listener.onError(getHalDeviceId(), errorCode, 0 /* vendorCode */);
@@ -240,7 +317,8 @@
             if (listener != null) {
                 vibrateSuccess();
             }
-            result |= true; // we have a valid biometric, done
+            // we have a valid biometric that doesn't require confirmation, done
+            result |= !mRequireConfirmation;
             resetFailedAttempts();
             onStop();
         }
@@ -268,7 +346,7 @@
             if (mBundle != null) {
                 try {
                     mStatusBarService.showBiometricDialog(mBundle, mDialogReceiver,
-                            mAuthenticator.getType());
+                            getBiometricType(), mRequireConfirmation);
                 } catch (RemoteException e) {
                     Slog.e(getLogTag(), "Unable to show biometric dialog", e);
                 }
diff --git a/services/core/java/com/android/server/biometrics/BiometricPromptService.java b/services/core/java/com/android/server/biometrics/BiometricPromptService.java
deleted file mode 100644
index 29eda8b..0000000
--- a/services/core/java/com/android/server/biometrics/BiometricPromptService.java
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.biometrics;
-
-import static android.Manifest.permission.USE_BIOMETRIC;
-import static android.Manifest.permission.USE_FINGERPRINT;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.hardware.biometrics.BiometricAuthenticator;
-import android.hardware.biometrics.BiometricConstants;
-import android.hardware.biometrics.IBiometricPromptReceiver;
-import android.hardware.biometrics.IBiometricPromptService;
-import android.hardware.biometrics.IBiometricPromptServiceReceiver;
-import android.hardware.face.FaceManager;
-import android.hardware.face.IFaceService;
-import android.hardware.fingerprint.FingerprintManager;
-import android.hardware.fingerprint.IFingerprintService;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.UserHandle;
-import android.util.Slog;
-
-import com.android.internal.R;
-import com.android.internal.os.SomeArgs;
-import com.android.server.SystemService;
-
-import java.util.ArrayList;
-
-/**
- * System service that arbitrates the modality for BiometricPrompt to use.
- */
-public class BiometricPromptService extends SystemService {
-
-    private static final String TAG = "BiometricPromptService";
-
-    /**
-     * No biometric methods or nothing has been enrolled.
-     * Move/expose these in BiometricPrompt if we ever want to allow applications to "blacklist"
-     * modalities when calling authenticate().
-     */
-    private static final int BIOMETRIC_NONE = 0;
-
-    /**
-     * Constant representing fingerprint.
-     */
-    private static final int BIOMETRIC_FINGERPRINT = 1 << 0;
-
-    /**
-     * Constant representing iris.
-     */
-    private static final int BIOMETRIC_IRIS = 1 << 1;
-
-    /**
-     * Constant representing face.
-     */
-    private static final int BIOMETRIC_FACE = 1 << 2;
-
-    private static final int[] FEATURE_ID = {
-            BIOMETRIC_FINGERPRINT,
-            BIOMETRIC_IRIS,
-            BIOMETRIC_FACE
-    };
-
-    private final Handler mHandler;
-    private final boolean mHasFeatureFingerprint;
-    private final boolean mHasFeatureIris;
-    private final boolean mHasFeatureFace;
-
-    private IFingerprintService mFingerprintService;
-    private IFaceService mFaceService;
-
-    // Get and cache the available authenticator (manager) classes. Used since aidl doesn't support
-    // polymorphism :/
-    final ArrayList<Authenticator> mAuthenticators = new ArrayList<>();
-
-    // Cache the current service that's being used. This is the service which
-    // cancelAuthentication() must be forwarded to. This is just a cache, and the actual
-    // check (is caller the current client) is done in the <Biometric>Service.
-    // Since Settings/System (not application) is responsible for changing preference, this
-    // should be safe.
-    private int mCurrentModality;
-
-    private final class Authenticator {
-        int mType;
-        BiometricAuthenticator mAuthenticator;
-
-        Authenticator(int type, BiometricAuthenticator authenticator) {
-            mType = type;
-            mAuthenticator = authenticator;
-        }
-
-        int getType() {
-            return mType;
-        }
-
-        BiometricAuthenticator getAuthenticator() {
-            return mAuthenticator;
-        }
-    }
-
-    /**
-     * This is just a pass-through service that wraps Fingerprint, Iris, Face services. This service
-     * should not carry any state. The reality is we need to keep a tiny amount of state so that
-     * cancelAuthentication() can go to the right place.
-     */
-    private final class BiometricPromptServiceWrapper extends IBiometricPromptService.Stub {
-
-        @Override // Binder call
-        public void authenticate(IBinder token, long sessionId, int userId,
-                IBiometricPromptServiceReceiver receiver, int flags, String opPackageName,
-                Bundle bundle, IBiometricPromptReceiver dialogReceiver) throws RemoteException {
-            // Check the USE_BIOMETRIC permission here. In the BiometricService, check do the
-            // AppOps and foreground check.
-            checkPermission();
-
-            final int callingUid = Binder.getCallingUid();
-            final int callingPid = Binder.getCallingPid();
-            final int callingUserId = UserHandle.getCallingUserId();
-
-            mHandler.post(() -> {
-                mCurrentModality = checkAndGetBiometricModality(receiver);
-
-                try {
-                    // No polymorphism :(
-                    if (mCurrentModality == BIOMETRIC_FINGERPRINT) {
-                        mFingerprintService.authenticateFromService(token, sessionId, userId,
-                                receiver, flags, opPackageName, bundle, dialogReceiver,
-                                callingUid, callingPid, callingUserId);
-                    } else if (mCurrentModality == BIOMETRIC_IRIS) {
-                        Slog.w(TAG, "Unsupported modality");
-                    } else if (mCurrentModality == BIOMETRIC_FACE) {
-                        mFaceService.authenticateFromService(token, sessionId, userId,
-                                receiver, flags, opPackageName, bundle, dialogReceiver,
-                                callingUid, callingPid, callingUserId);
-                    } else {
-                        Slog.w(TAG, "Unsupported modality");
-                    }
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "Unable to start authentication", e);
-                }
-            });
-        }
-
-        @Override // Binder call
-        public void cancelAuthentication(IBinder token, String opPackageName)
-                throws RemoteException {
-            checkPermission();
-
-            final int callingUid = Binder.getCallingUid();
-            final int callingPid = Binder.getCallingPid();
-            final int callingUserId = UserHandle.getCallingUserId();
-
-            mHandler.post(() -> {
-                try {
-                    if (mCurrentModality == BIOMETRIC_FINGERPRINT) {
-                        mFingerprintService.cancelAuthenticationFromService(token, opPackageName,
-                                callingUid, callingPid, callingUserId);
-                    } else if (mCurrentModality == BIOMETRIC_IRIS) {
-                        Slog.w(TAG, "Unsupported modality");
-                    } else if (mCurrentModality == BIOMETRIC_FACE) {
-                        mFaceService.cancelAuthenticationFromService(token, opPackageName,
-                                callingUid, callingPid, callingUserId);
-                    } else {
-                        Slog.w(TAG, "Unsupported modality");
-                    }
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "Unable to cancel authentication");
-                }
-            });
-        }
-    }
-
-    private void checkPermission() {
-        if (getContext().checkCallingPermission(USE_FINGERPRINT)
-                != PackageManager.PERMISSION_GRANTED) {
-            getContext().enforceCallingPermission(USE_BIOMETRIC,
-                    "Must have USE_BIOMETRIC permission");
-        }
-    }
-
-    /**
-     * Initializes the system service.
-     * <p>
-     * Subclasses must define a single argument constructor that accepts the context
-     * and passes it to super.
-     * </p>
-     *
-     * @param context The system server context.
-     */
-    public BiometricPromptService(Context context) {
-        super(context);
-
-        mHandler = new Handler(Looper.getMainLooper());
-
-        final PackageManager pm = context.getPackageManager();
-        mHasFeatureFingerprint = pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
-        mHasFeatureIris = pm.hasSystemFeature(PackageManager.FEATURE_IRIS);
-        mHasFeatureFace = pm.hasSystemFeature(PackageManager.FEATURE_FACE);
-    }
-
-    @Override
-    public void onStart() {
-        // TODO: maybe get these on-demand
-        if (mHasFeatureFingerprint) {
-            mFingerprintService = IFingerprintService.Stub.asInterface(
-                    ServiceManager.getService(Context.FINGERPRINT_SERVICE));
-        }
-        if (mHasFeatureFace) {
-            mFaceService = IFaceService.Stub.asInterface(
-                    ServiceManager.getService(Context.FACE_SERVICE));
-        }
-
-        // Cache the authenticators
-        for (int i = 0; i < FEATURE_ID.length; i++) {
-            if (hasFeature(FEATURE_ID[i])) {
-                Authenticator authenticator =
-                        new Authenticator(FEATURE_ID[i], getAuthenticator(FEATURE_ID[i]));
-                mAuthenticators.add(authenticator);
-            }
-        }
-
-        publishBinderService(Context.BIOMETRIC_PROMPT_SERVICE, new BiometricPromptServiceWrapper());
-    }
-
-    /**
-     * Checks if there are any available biometrics, and returns the modality. This method also
-     * returns errors through the callback (no biometric feature, hardware not detected, no
-     * templates enrolled, etc). This service must not start authentication if errors are sent.
-     */
-    private int checkAndGetBiometricModality(IBiometricPromptServiceReceiver receiver) {
-        int modality = BIOMETRIC_NONE;
-        final String hardwareUnavailable =
-                getContext().getString(R.string.biometric_error_hw_unavailable);
-
-        // No biometric features, send error
-        if (mAuthenticators.isEmpty()) {
-            try {
-                receiver.onError(0 /* deviceId */,
-                        BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT,
-                        hardwareUnavailable);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Unable to send error", e);
-            }
-            return BIOMETRIC_NONE;
-        }
-
-        // Find first authenticator that's both detected and enrolled
-        boolean isHardwareDetected = false;
-        boolean hasTemplatesEnrolled = false;
-        for (int i = 0; i < mAuthenticators.size(); i++) {
-            int featureId = mAuthenticators.get(i).getType();
-            BiometricAuthenticator authenticator = mAuthenticators.get(i).getAuthenticator();
-            if (authenticator.isHardwareDetected()) {
-                isHardwareDetected = true;
-                if (authenticator.hasEnrolledTemplates()) {
-                    hasTemplatesEnrolled = true;
-                    modality = featureId;
-                    break;
-                }
-            }
-        }
-
-        // Check error conditions
-        if (!isHardwareDetected) {
-            try {
-                receiver.onError(0 /* deviceId */,
-                        BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
-                        hardwareUnavailable);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Unable to send error", e);
-            }
-            return BIOMETRIC_NONE;
-        }
-        if (!hasTemplatesEnrolled) {
-            try {
-                receiver.onError(0 /* deviceId */,
-                        BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS,
-                        hardwareUnavailable);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Unable to send error", e);
-            }
-            return BIOMETRIC_NONE;
-        }
-
-        return modality;
-    }
-
-    private BiometricAuthenticator getAuthenticator(int type) {
-        switch (type) {
-            case BIOMETRIC_FINGERPRINT:
-                return (FingerprintManager)
-                        getContext().getSystemService(Context.FINGERPRINT_SERVICE);
-            case BIOMETRIC_IRIS:
-                return null;
-            case BIOMETRIC_FACE:
-                return (FaceManager)
-                        getContext().getSystemService(Context.FACE_SERVICE);
-            default:
-                return null;
-        }
-    }
-
-    private boolean hasFeature(int type) {
-        switch (type) {
-            case BIOMETRIC_FINGERPRINT:
-                return mHasFeatureFingerprint;
-            case BIOMETRIC_IRIS:
-                return mHasFeatureIris;
-            case BIOMETRIC_FACE:
-                return mHasFeatureFace;
-            default:
-                return false;
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index a181b61..87cf9c4 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -11,506 +11,248 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
  */
 
 package com.android.server.biometrics;
 
-import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
+import static android.Manifest.permission.USE_BIOMETRIC;
+import static android.Manifest.permission.USE_FINGERPRINT;
 
-import android.app.ActivityManager;
-import android.app.ActivityTaskManager;
-import android.app.AlarmManager;
 import android.app.AppOpsManager;
-import android.app.IActivityTaskManager;
-import android.app.PendingIntent;
-import android.app.SynchronousUserSwitchObserver;
-import android.app.TaskStackListener;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.PackageManager;
-import android.content.pm.UserInfo;
 import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.BiometricConstants;
 import android.hardware.biometrics.IBiometricPromptReceiver;
-import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
-import android.hardware.fingerprint.Fingerprint;
+import android.hardware.biometrics.IBiometricService;
+import android.hardware.biometrics.IBiometricServiceReceiver;
+import android.hardware.face.FaceManager;
+import android.hardware.face.IFaceService;
+import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.IFingerprintService;
 import android.os.Binder;
 import android.os.Bundle;
-import android.os.DeadObjectException;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.IHwBinder;
-import android.os.IRemoteCallback;
-import android.os.PowerManager;
+import android.os.Looper;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.SystemClock;
 import android.os.UserHandle;
-import android.os.UserManager;
-import android.security.KeyStore;
+import android.provider.Settings;
 import android.util.Slog;
-import android.util.SparseBooleanArray;
-import android.util.SparseIntArray;
 
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.R;
 import com.android.server.SystemService;
-import com.android.server.biometrics.fingerprint.FingerprintService;
 
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
 
 /**
- * Abstract base class containing all of the business logic for biometric services, e.g.
- * Fingerprint, Face, Iris.
- *
- * @hide
+ * System service that arbitrates the modality for BiometricPrompt to use.
  */
-public abstract class BiometricService extends SystemService implements IHwBinder.DeathRecipient {
+public class BiometricService extends SystemService {
 
-    protected static final boolean DEBUG = true;
+    private static final String TAG = "BiometricPromptService";
 
-    private static final String KEY_LOCKOUT_RESET_USER = "lockout_reset_user";
-    private static final int MSG_USER_SWITCHING = 10;
-    private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30 * 1000;
-    private static final long CANCEL_TIMEOUT_LIMIT = 3000; // max wait for onCancel() from HAL,in ms
+    /**
+     * No biometric methods or nothing has been enrolled.
+     * Move/expose these in BiometricPrompt if we ever want to allow applications to "blacklist"
+     * modalities when calling authenticate().
+     */
+    private static final int BIOMETRIC_NONE = 0;
 
-    private final Context mContext;
-    private final String mKeyguardPackage;
+    /**
+     * Constant representing fingerprint.
+     */
+    private static final int BIOMETRIC_FINGERPRINT = 1 << 0;
+
+    /**
+     * Constant representing iris.
+     */
+    private static final int BIOMETRIC_IRIS = 1 << 1;
+
+    /**
+     * Constant representing face.
+     */
+    private static final int BIOMETRIC_FACE = 1 << 2;
+
+    private static final int[] FEATURE_ID = {
+            BIOMETRIC_FINGERPRINT,
+            BIOMETRIC_IRIS,
+            BIOMETRIC_FACE
+    };
+
     private final AppOpsManager mAppOps;
-    private final SparseBooleanArray mTimedLockoutCleared;
-    private final SparseIntArray mFailedAttempts;
-    private final IActivityTaskManager mActivityTaskManager;
-    private final AlarmManager mAlarmManager;
-    private final PowerManager mPowerManager;
-    private final UserManager mUserManager;
-    private final MetricsLogger mMetricsLogger;
-    private final BiometricTaskStackListener mTaskStackListener = new BiometricTaskStackListener();
-    private final ResetClientStateRunnable mResetClientState = new ResetClientStateRunnable();
-    private final LockoutReceiver mLockoutReceiver = new LockoutReceiver();
-    private final ArrayList<LockoutResetMonitor> mLockoutMonitors = new ArrayList<>();
+    private final Handler mHandler;
+    private final boolean mHasFeatureFingerprint;
+    private final boolean mHasFeatureIris;
+    private final boolean mHasFeatureFace;
 
-    protected final IStatusBarService mStatusBarService;
-    protected final Map<Integer, Long> mAuthenticatorIds =
-            Collections.synchronizedMap(new HashMap<>());
-    protected final ResetFailedAttemptsForUserRunnable mResetFailedAttemptsForCurrentUserRunnable =
-            new ResetFailedAttemptsForUserRunnable();
-    protected final H mHandler = new H();
+    private IFingerprintService mFingerprintService;
+    private IFaceService mFaceService;
 
-    private ClientMonitor mCurrentClient;
-    private ClientMonitor mPendingClient;
-    private PerformanceStats mPerformanceStats;
-    protected int mCurrentUserId = UserHandle.USER_NULL;
-    // Normal authentications are tracked by mPerformanceMap.
-    protected HashMap<Integer, PerformanceStats> mPerformanceMap = new HashMap<>();
-    // Transactions that make use of CryptoObjects are tracked by mCryptoPerformaceMap.
-    protected HashMap<Integer, PerformanceStats> mCryptoPerformanceMap = new HashMap<>();
+    // Get and cache the available authenticator (manager) classes. Used since aidl doesn't support
+    // polymorphism :/
+    final ArrayList<Authenticator> mAuthenticators = new ArrayList<>();
 
-    protected class PerformanceStats {
-        public int accept; // number of accepted biometrics
-        public int reject; // number of rejected biometrics
-        public int acquire; // total number of acquisitions. Should be >= accept+reject due to poor
-        // image acquisition in some cases (too fast, too slow, dirty sensor, etc.)
-        public int lockout; // total number of lockouts
-        public int permanentLockout; // total number of permanent lockouts
+    // Cache the current service that's being used. This is the service which
+    // cancelAuthentication() must be forwarded to. This is just a cache, and the actual
+    // check (is caller the current client) is done in the <Biometric>Service.
+    // Since Settings/System (not application) is responsible for changing preference, this
+    // should be safe.
+    private int mCurrentModality;
+
+    private final class Authenticator {
+        int mType;
+        BiometricAuthenticator mAuthenticator;
+
+        Authenticator(int type, BiometricAuthenticator authenticator) {
+            mType = type;
+            mAuthenticator = authenticator;
+        }
+
+        int getType() {
+            return mType;
+        }
+
+        BiometricAuthenticator getAuthenticator() {
+            return mAuthenticator;
+        }
     }
 
     /**
-     * @return the log tag.
+     * This is just a pass-through service that wraps Fingerprint, Iris, Face services. This service
+     * should not carry any state. The reality is we need to keep a tiny amount of state so that
+     * cancelAuthentication() can go to the right place.
      */
-    protected abstract String getTag();
+    private final class BiometricPromptServiceWrapper extends IBiometricService.Stub {
 
-    /**
-     * @return the biometric utilities for a specific implementation.
-     */
-    protected abstract BiometricUtils getBiometricUtils();
+        @Override // Binder call
+        public void authenticate(IBinder token, long sessionId, int userId,
+                IBiometricServiceReceiver receiver, int flags, String opPackageName,
+                Bundle bundle, IBiometricPromptReceiver dialogReceiver) throws RemoteException {
+            // Check the USE_BIOMETRIC permission here. In the BiometricService, check do the
+            // AppOps and foreground check.
+            checkPermission();
 
-    /**
-     * @return the number of failed attempts after which the user will be temporarily locked out
-     *         from using the biometric. A strong auth (pin/pattern/pass) clears this counter.
-     */
-    protected abstract int getFailedAttemptsLockoutTimed();
-
-    /**
-     * @return the number of failed attempts after which the user will be permanently locked out
-     *         from using the biometric. A strong auth (pin/pattern/pass) clears this counter.
-     */
-    protected abstract int getFailedAttemptsLockoutPermanent();
-
-    /**
-     * @return the metrics constants for a biometric implementation.
-     */
-    protected abstract Metrics getMetrics();
-
-    /**
-     * @param userId
-     * @return true if the enrollment limit has been reached.
-     */
-    protected abstract boolean hasReachedEnrollmentLimit(int userId);
-
-    /**
-     * Notifies the HAL that the user has changed.
-     * @param userId
-     * @param clientPackage
-     */
-    protected abstract void updateActiveGroup(int userId, String clientPackage);
-
-    /**
-     * @return The protected intent to reset lockout for a specific biometric.
-     */
-    protected abstract String getLockoutResetIntent();
-
-    /**
-     * @return The permission the sender is required to have in order for the lockout reset intent
-     *         to be received by the BiometricService implementation.
-     */
-    protected abstract String getLockoutBroadcastPermission();
-
-    /**
-     * @return The HAL ID.
-     */
-    protected abstract long getHalDeviceId();
-
-    /**
-     * This method is called when the user switches. Implementations should probably notify the
-     * HAL.
-     * @param userId
-     */
-    protected abstract void handleUserSwitching(int userId);
-
-    /**
-     * @param userId
-     * @return Returns true if the user has any enrolled biometrics.
-     */
-    protected abstract boolean hasEnrolledBiometrics(int userId);
-
-    /**
-     * @return Returns the MANAGE_* permission string, which is required for enrollment, removal
-     * etc.
-     */
-    protected abstract String getManageBiometricPermission();
-
-    /**
-     * Checks if the caller has permission to use the biometric service - throws a SecurityException
-     * if not.
-     */
-    protected abstract void checkUseBiometricPermission();
-
-    /**
-     * @return Returns one of the {@link AppOpsManager} constants which pertains to the specific
-     *         biometric service.
-     */
-    protected abstract int getAppOp();
-
-
-    /**
-     * Notifies clients of any change in the biometric state (active / idle). This is mainly for
-     * Fingerprint navigation gestures.
-     * @param isActive
-     */
-    protected void notifyClientActiveCallbacks(boolean isActive) {}
-
-    protected class AuthenticationClientImpl extends AuthenticationClient {
-
-        public AuthenticationClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
-                IBinder token, ServiceListener listener, int targetUserId, int groupId, long opId,
-                boolean restricted, String owner, Bundle bundle,
-                IBiometricPromptReceiver dialogReceiver,
-                IStatusBarService statusBarService, BiometricAuthenticator authenticator) {
-            super(context, getMetrics(), daemon, halDeviceId, token, listener,
-                    targetUserId, groupId, opId, restricted, owner, bundle, dialogReceiver,
-                    statusBarService, authenticator);
-        }
-
-        @Override
-        public void onStart() {
-            try {
-                mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
-            } catch (RemoteException e) {
-                Slog.e(getTag(), "Could not register task stack listener", e);
-            }
-        }
-
-        @Override
-        public void onStop() {
-            try {
-                mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
-            } catch (RemoteException e) {
-                Slog.e(getTag(), "Could not unregister task stack listener", e);
-            }
-        }
-
-        @Override
-        public void resetFailedAttempts() {
-            resetFailedAttemptsForUser(true /* clearAttemptCounter */,
-                    ActivityManager.getCurrentUser());
-        }
-
-        @Override
-        public void notifyUserActivity() {
-            userActivity();
-        }
-
-        @Override
-        public int handleFailedAttempt() {
-            final int currentUser = ActivityManager.getCurrentUser();
-            mFailedAttempts.put(currentUser, mFailedAttempts.get(currentUser, 0) + 1);
-            mTimedLockoutCleared.put(ActivityManager.getCurrentUser(), false);
-            final int lockoutMode = getLockoutMode();
-            if (lockoutMode == AuthenticationClient.LOCKOUT_PERMANENT) {
-                mPerformanceStats.permanentLockout++;
-            } else if (lockoutMode == AuthenticationClient.LOCKOUT_TIMED) {
-                mPerformanceStats.lockout++;
+            if (token == null || receiver == null || opPackageName == null || bundle == null
+                    || dialogReceiver == null) {
+                Slog.e(TAG, "Unable to authenticate, one or more null arguments");
+                return;
             }
 
-            // Failing multiple times will continue to push out the lockout time
-            if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
-                scheduleLockoutResetForUser(currentUser);
-                return lockoutMode;
-            }
-            return AuthenticationClient.LOCKOUT_NONE;
-        }
-    }
+            final int callingUid = Binder.getCallingUid();
+            final int callingPid = Binder.getCallingPid();
+            final int callingUserId = UserHandle.getCallingUserId();
 
-    protected class EnrollClientImpl extends EnrollClient {
+            mHandler.post(() -> {
+                mCurrentModality = checkAndGetBiometricModality(receiver);
 
-        public EnrollClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
-                IBinder token, ServiceListener listener, int userId, int groupId,
-                byte[] cryptoToken, boolean restricted, String owner) {
-            super(context, getMetrics(), daemon, halDeviceId, token, listener,
-                    userId, groupId, cryptoToken, restricted, owner, getBiometricUtils());
-        }
-
-        @Override
-        public void notifyUserActivity() {
-            userActivity();
-        }
-    }
-
-    protected class RemovalClientImpl extends RemovalClient {
-        private boolean mShouldNotify;
-
-        public RemovalClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
-                IBinder token, ServiceListener listener, int fingerId, int groupId, int userId,
-                boolean restricted, String owner) {
-            super(context, getMetrics(), daemon, halDeviceId, token, listener, fingerId, groupId,
-                    userId, restricted, owner, getBiometricUtils());
-        }
-
-        public void setShouldNotifyUserActivity(boolean shouldNotify) {
-            mShouldNotify = shouldNotify;
-        }
-
-        @Override
-        public void notifyUserActivity() {
-            if (mShouldNotify) {
-                userActivity();
-            }
-        }
-    }
-
-    protected class EnumerateClientImpl extends EnumerateClient {
-
-        public EnumerateClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
-                IBinder token, ServiceListener listener, int groupId, int userId,
-                boolean restricted, String owner) {
-            super(context, getMetrics(), daemon, halDeviceId, token, listener, groupId, userId,
-                    restricted, owner);
-        }
-
-        @Override
-        public void notifyUserActivity() {
-            userActivity();
-        }
-    }
-
-    /**
-     * Wraps the callback interface from Service -> Manager
-     */
-    protected interface ServiceListener {
-        default void onEnrollResult(BiometricAuthenticator.Identifier identifier,
-                int remaining) throws RemoteException {};
-
-        void onAcquired(long deviceId, int acquiredInfo, int vendorCode)
-                throws RemoteException;
-
-        void onAuthenticationSucceeded(long deviceId,
-                BiometricAuthenticator.Identifier biometric, int userId)
-                throws RemoteException;
-
-        void onAuthenticationFailed(long deviceId)
-                throws RemoteException;
-
-        void onError(long deviceId, int error, int vendorCode)
-                throws RemoteException;
-
-        default void onRemoved(BiometricAuthenticator.Identifier identifier,
-                int remaining) throws RemoteException {};
-
-        default void onEnumerated(BiometricAuthenticator.Identifier identifier,
-                int remaining) throws RemoteException {};
-    }
-
-    /**
-     * Wraps a portion of the interface from Service -> Daemon that is used by the ClientMonitor
-     * subclasses.
-     */
-    protected interface DaemonWrapper {
-        int ERROR_ESRCH = 3; // Likely fingerprint HAL is dead. see errno.h.
-        int authenticate(long operationId, int groupId) throws RemoteException;
-        int cancel() throws RemoteException;
-        int remove(int groupId, int biometricId) throws RemoteException;
-        int enumerate() throws RemoteException;
-        int enroll(byte[] cryptoToken, int groupId, int timeout) throws RemoteException;
-    }
-
-    /**
-     * Handler which all subclasses should post events to.
-     */
-    protected final class H extends Handler {
-        @Override
-        public void handleMessage(android.os.Message msg) {
-            switch (msg.what) {
-                case MSG_USER_SWITCHING:
-                    handleUserSwitching(msg.arg1);
-                    break;
-
-                default:
-                    Slog.w(getTag(), "Unknown message:" + msg.what);
-            }
-        }
-    }
-
-    private final class BiometricTaskStackListener extends TaskStackListener {
-        @Override
-        public void onTaskStackChanged() {
-            try {
-                if (!(mCurrentClient instanceof AuthenticationClient)) {
-                    return;
+                try {
+                    // No polymorphism :(
+                    if (mCurrentModality == BIOMETRIC_FINGERPRINT) {
+                        mFingerprintService.authenticateFromService(token, sessionId, userId,
+                                receiver, flags, opPackageName, bundle, dialogReceiver,
+                                callingUid, callingPid, callingUserId);
+                    } else if (mCurrentModality == BIOMETRIC_IRIS) {
+                        Slog.w(TAG, "Unsupported modality");
+                    } else if (mCurrentModality == BIOMETRIC_FACE) {
+                        // If the user disabled face for apps, return ERROR_HW_UNAVAILABLE
+                        if (isFaceEnabledForApps()) {
+                            receiver.onError(0 /* deviceId */,
+                                    BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
+                                    FaceManager.getErrorString(getContext(),
+                                            BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
+                                            0 /* vendorCode */));
+                        } else {
+                            mFaceService.authenticateFromService(true /* requireConfirmation */,
+                                    token, sessionId, userId, receiver, flags, opPackageName,
+                                    bundle, dialogReceiver, callingUid, callingPid, callingUserId);
+                        }
+                    } else {
+                        Slog.w(TAG, "Unsupported modality");
+                    }
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Unable to start authentication", e);
                 }
-                final String currentClient = mCurrentClient.getOwnerString();
-                if (isKeyguard(currentClient)) {
-                    return; // Keyguard is always allowed
+            });
+        }
+
+        private boolean isFaceEnabledForApps() {
+            // TODO: maybe cache this and eliminate duplicated code with KeyguardUpdateMonitor
+            return Settings.Secure.getIntForUser(
+                    getContext().getContentResolver(),
+                    Settings.Secure.FACE_UNLOCK_APP_ENABLED,
+                    1 /* default */,
+                    UserHandle.USER_CURRENT) == 0;
+        }
+
+        @Override // Binder call
+        public void cancelAuthentication(IBinder token, String opPackageName)
+                throws RemoteException {
+            checkPermission();
+
+            if (token == null || opPackageName == null) {
+                Slog.e(TAG, "Unable to cancel, one or more null arguments");
+                return;
+            }
+
+            final int callingUid = Binder.getCallingUid();
+            final int callingPid = Binder.getCallingPid();
+            final int callingUserId = UserHandle.getCallingUserId();
+
+            mHandler.post(() -> {
+                try {
+                    if (mCurrentModality == BIOMETRIC_FINGERPRINT) {
+                        mFingerprintService.cancelAuthenticationFromService(token, opPackageName,
+                                callingUid, callingPid, callingUserId);
+                    } else if (mCurrentModality == BIOMETRIC_IRIS) {
+                        Slog.w(TAG, "Unsupported modality");
+                    } else if (mCurrentModality == BIOMETRIC_FACE) {
+                        mFaceService.cancelAuthenticationFromService(token, opPackageName,
+                                callingUid, callingPid, callingUserId);
+                    } else {
+                        Slog.w(TAG, "Unsupported modality");
+                    }
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Unable to cancel authentication");
                 }
-                List<ActivityManager.RunningTaskInfo> runningTasks =
-                        mActivityTaskManager.getTasks(1);
-                if (!runningTasks.isEmpty()) {
-                    final String topPackage = runningTasks.get(0).topActivity.getPackageName();
-                    if (!topPackage.contentEquals(currentClient)) {
-                        Slog.e(getTag(), "Stopping background authentication, top: " + topPackage
-                                + " currentClient: " + currentClient);
-                        mCurrentClient.stop(false /* initiatedByClient */);
+            });
+        }
+
+        @Override // Binder call
+        public boolean hasEnrolledBiometrics(String opPackageName) {
+            checkPermission();
+
+            if (mAppOps.noteOp(AppOpsManager.OP_USE_BIOMETRIC, Binder.getCallingUid(),
+                    opPackageName) != AppOpsManager.MODE_ALLOWED) {
+                Slog.w(TAG, "Rejecting " + opPackageName + "; permission denied");
+                throw new SecurityException("Permission denied");
+            }
+
+            final long ident = Binder.clearCallingIdentity();
+            boolean hasEnrolled = false;
+            try {
+                // Note: On devices with multi-modal authentication, the selection logic will need
+                // to be updated.
+                for (int i = 0; i < mAuthenticators.size(); i++) {
+                    if (mAuthenticators.get(i).getAuthenticator().hasEnrolledTemplates()) {
+                        hasEnrolled = true;
+                        break;
                     }
                 }
-            } catch (RemoteException e) {
-                Slog.e(getTag(), "Unable to get running tasks", e);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
             }
+            return hasEnrolled;
         }
     }
 
-    private final class ResetClientStateRunnable implements Runnable {
-        @Override
-        public void run() {
-            /**
-             * Warning: if we get here, the driver never confirmed our call to cancel the current
-             * operation (authenticate, enroll, remove, enumerate, etc), which is
-             * really bad.  The result will be a 3-second delay in starting each new client.
-             * If you see this on a device, make certain the driver notifies with
-             * {@link BiometricConstants#BIOMETRIC_ERROR_CANCELED} in response to cancel()
-             * once it has successfully switched to the IDLE state in the HAL.
-             * Additionally,{@link BiometricConstants#BIOMETRIC_ERROR_CANCELED} should only be sent
-             * in response to an actual cancel() call.
-             */
-            Slog.w(getTag(), "Client "
-                    + (mCurrentClient != null ? mCurrentClient.getOwnerString() : "null")
-                    + " failed to respond to cancel, starting client "
-                    + (mPendingClient != null ? mPendingClient.getOwnerString() : "null"));
-
-            mCurrentClient = null;
-            startClient(mPendingClient, false);
-        }
-    }
-
-    private final class LockoutReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            Slog.v(getTag(), "Resetting lockout: " + intent.getAction());
-            if (getLockoutResetIntent().equals(intent.getAction())) {
-                final int user = intent.getIntExtra(KEY_LOCKOUT_RESET_USER, 0);
-                resetFailedAttemptsForUser(false /* clearAttemptCounter */, user);
-            }
-        }
-    }
-
-    private final class ResetFailedAttemptsForUserRunnable implements Runnable {
-        @Override
-        public void run() {
-            resetFailedAttemptsForUser(true /* clearAttemptCounter */,
-                    ActivityManager.getCurrentUser());
-        }
-    }
-
-    private final class LockoutResetMonitor implements IBinder.DeathRecipient {
-        private static final long WAKELOCK_TIMEOUT_MS = 2000;
-        private final IBiometricServiceLockoutResetCallback mCallback;
-        private final PowerManager.WakeLock mWakeLock;
-
-        public LockoutResetMonitor(IBiometricServiceLockoutResetCallback callback) {
-            mCallback = callback;
-            mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
-                    "lockout reset callback");
-            try {
-                mCallback.asBinder().linkToDeath(LockoutResetMonitor.this, 0);
-            } catch (RemoteException e) {
-                Slog.w(getTag(), "caught remote exception in linkToDeath", e);
-            }
-        }
-
-        public void sendLockoutReset() {
-            if (mCallback != null) {
-                try {
-                    mWakeLock.acquire(WAKELOCK_TIMEOUT_MS);
-                    mCallback.onLockoutReset(getHalDeviceId(), new IRemoteCallback.Stub() {
-                        @Override
-                        public void sendResult(Bundle data) throws RemoteException {
-                            releaseWakelock();
-                        }
-                    });
-                } catch (DeadObjectException e) {
-                    Slog.w(getTag(), "Death object while invoking onLockoutReset: ", e);
-                    mHandler.post(mRemoveCallbackRunnable);
-                } catch (RemoteException e) {
-                    Slog.w(getTag(), "Failed to invoke onLockoutReset: ", e);
-                    releaseWakelock();
-                }
-            }
-        }
-
-        private final Runnable mRemoveCallbackRunnable = new Runnable() {
-            @Override
-            public void run() {
-                releaseWakelock();
-                removeLockoutResetCallback(LockoutResetMonitor.this);
-            }
-        };
-
-        @Override
-        public void binderDied() {
-            Slog.e(getTag(), "Lockout reset callback binder died");
-            mHandler.post(mRemoveCallbackRunnable);
-        }
-
-        private void releaseWakelock() {
-            if (mWakeLock.isHeld()) {
-                mWakeLock.release();
-            }
+    private void checkPermission() {
+        if (getContext().checkCallingPermission(USE_FINGERPRINT)
+                != PackageManager.PERMISSION_GRANTED) {
+            getContext().enforceCallingPermission(USE_BIOMETRIC,
+                    "Must have USE_BIOMETRIC permission");
         }
     }
 
@@ -525,588 +267,130 @@
      */
     public BiometricService(Context context) {
         super(context);
-        mContext = context;
-        mStatusBarService = IStatusBarService.Stub.asInterface(
-                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
-        mKeyguardPackage = ComponentName.unflattenFromString(context.getResources().getString(
-                com.android.internal.R.string.config_keyguardComponent)).getPackageName();
+
         mAppOps = context.getSystemService(AppOpsManager.class);
-        mTimedLockoutCleared = new SparseBooleanArray();
-        mFailedAttempts = new SparseIntArray();
-        mActivityTaskManager = ((ActivityTaskManager) context.getSystemService(
-                Context.ACTIVITY_TASK_SERVICE)).getService();
-        mPowerManager = mContext.getSystemService(PowerManager.class);
-        mAlarmManager = mContext.getSystemService(AlarmManager.class);
-        mUserManager = UserManager.get(mContext);
-        mMetricsLogger = new MetricsLogger();
-        mContext.registerReceiver(mLockoutReceiver, new IntentFilter(getLockoutResetIntent()),
-                getLockoutBroadcastPermission(), null /* handler */);
+        mHandler = new Handler(Looper.getMainLooper());
+
+        final PackageManager pm = context.getPackageManager();
+        mHasFeatureFingerprint = pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
+        mHasFeatureIris = pm.hasSystemFeature(PackageManager.FEATURE_IRIS);
+        mHasFeatureFace = pm.hasSystemFeature(PackageManager.FEATURE_FACE);
     }
 
     @Override
     public void onStart() {
-        listenForUserSwitches();
-    }
+        // TODO: maybe get these on-demand
+        if (mHasFeatureFingerprint) {
+            mFingerprintService = IFingerprintService.Stub.asInterface(
+                    ServiceManager.getService(Context.FINGERPRINT_SERVICE));
+        }
+        if (mHasFeatureFace) {
+            mFaceService = IFaceService.Stub.asInterface(
+                    ServiceManager.getService(Context.FACE_SERVICE));
+        }
 
-    @Override
-    public void serviceDied(long cookie) {
-        Slog.e(getTag(), "HAL died");
-        mMetricsLogger.count(getMetrics().tagHalDied(), 1);
-        handleError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
-                0 /*vendorCode */);
-    }
+        // Cache the authenticators
+        for (int i = 0; i < FEATURE_ID.length; i++) {
+            if (hasFeature(FEATURE_ID[i])) {
+                Authenticator authenticator =
+                        new Authenticator(FEATURE_ID[i], getAuthenticator(FEATURE_ID[i]));
+                mAuthenticators.add(authenticator);
+            }
+        }
 
-    protected ClientMonitor getCurrentClient() {
-        return mCurrentClient;
-    }
-
-    protected ClientMonitor getPendingClient() {
-        return mPendingClient;
+        publishBinderService(Context.BIOMETRIC_SERVICE, new BiometricPromptServiceWrapper());
     }
 
     /**
-     * Callback handlers from the daemon. The caller must put this on a handler.
+     * Checks if there are any available biometrics, and returns the modality. This method also
+     * returns errors through the callback (no biometric feature, hardware not detected, no
+     * templates enrolled, etc). This service must not start authentication if errors are sent.
      */
+    private int checkAndGetBiometricModality(IBiometricServiceReceiver receiver) {
+        int modality = BIOMETRIC_NONE;
+        final String hardwareUnavailable =
+                getContext().getString(R.string.biometric_error_hw_unavailable);
 
-    protected void handleAcquired(long deviceId, int acquiredInfo, int vendorCode) {
-        ClientMonitor client = mCurrentClient;
-        if (client != null && client.onAcquired(acquiredInfo, vendorCode)) {
-            removeClient(client);
-        }
-        if (mPerformanceStats != null && getLockoutMode() == AuthenticationClient.LOCKOUT_NONE
-                && client instanceof AuthenticationClient) {
-            // ignore enrollment acquisitions or acquisitions when we're locked out
-            mPerformanceStats.acquire++;
-        }
-    }
-
-    protected void handleAuthenticated(BiometricAuthenticator.Identifier identifier,
-            ArrayList<Byte> token) {
-        ClientMonitor client = mCurrentClient;
-        final boolean authenticated = identifier.getBiometricId() != 0;
-
-        if (authenticated) {
-            final byte[] byteToken = new byte[token.size()];
-            for (int i = 0; i < token.size(); i++) {
-                byteToken[i] = token.get(i);
+        // No biometric features, send error
+        if (mAuthenticators.isEmpty()) {
+            try {
+                receiver.onError(0 /* deviceId */,
+                        BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT,
+                        hardwareUnavailable);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Unable to send error", e);
             }
-            KeyStore.getInstance().addAuthToken(byteToken);
-        }
-        if (client != null && client.onAuthenticated(identifier, authenticated)) {
-            removeClient(client);
-        }
-        if (authenticated) {
-            mPerformanceStats.accept++;
-        } else {
-            mPerformanceStats.reject++;
-        }
-    }
-
-    protected void handleEnrollResult(BiometricAuthenticator.Identifier identifier,
-            int remaining) {
-        ClientMonitor client = mCurrentClient;
-        if (client != null && client.onEnrollResult(identifier, remaining)) {
-            removeClient(client);
-            // When enrollment finishes, update this group's authenticator id, as the HAL has
-            // already generated a new authenticator id when the new biometric is enrolled.
-            if (identifier instanceof Fingerprint) {
-                updateActiveGroup(((Fingerprint)identifier).getGroupId(), null);
-            } else {
-                updateActiveGroup(mCurrentUserId, null);
-            }
-
-        }
-    }
-
-    protected void handleError(long deviceId, int error, int vendorCode) {
-        final ClientMonitor client = mCurrentClient;
-
-        if (DEBUG) Slog.v(getTag(), "handleError(client="
-                + (client != null ? client.getOwnerString() : "null") + ", error = " + error + ")");
-
-        if (client != null && client.onError(deviceId, error, vendorCode)) {
-            removeClient(client);
+            return BIOMETRIC_NONE;
         }
 
-        if (error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) {
-            mHandler.removeCallbacks(mResetClientState);
-            if (mPendingClient != null) {
-                if (DEBUG) Slog.v(getTag(), "start pending client " + mPendingClient.getOwnerString());
-                startClient(mPendingClient, false);
-                mPendingClient = null;
-            }
-        }
-    }
-
-    protected void handleRemoved(BiometricAuthenticator.Identifier identifier,
-            final int remaining) {
-        if (DEBUG) Slog.w(getTag(), "Removed: fid=" + identifier.getBiometricId()
-                + ", dev=" + identifier.getDeviceId()
-                + ", rem=" + remaining);
-
-        ClientMonitor client = mCurrentClient;
-        if (client != null && client.onRemoved(identifier, remaining)) {
-            removeClient(client);
-            // When the last biometric of a group is removed, update the authenticator id
-            int userId = mCurrentUserId;
-            if (identifier instanceof Fingerprint) {
-                userId = ((Fingerprint) identifier).getGroupId();
-            }
-            if (!hasEnrolledBiometrics(userId)) {
-                updateActiveGroup(userId, null);
-            }
-        }
-    }
-
-    /**
-     * Calls from the Manager. These are still on the calling binder's thread.
-     */
-
-    protected void enrollInternal(EnrollClientImpl client, int userId) {
-        if (hasReachedEnrollmentLimit(userId)) {
-            return;
-        }
-
-        // Group ID is arbitrarily set to parent profile user ID. It just represents
-        // the default biometrics for the user.
-        if (!isCurrentUserOrProfile(userId)) {
-            return;
-        }
-
-        mHandler.post(() -> {
-            startClient(client, true /* initiatedByClient */);
-        });
-    }
-
-    protected void cancelEnrollmentInternal(IBinder token) {
-        mHandler.post(() -> {
-            ClientMonitor client = mCurrentClient;
-            if (client instanceof EnrollClient && client.getToken() == token) {
-                client.stop(client.getToken() == token);
-            }
-        });
-    }
-
-    protected void authenticateInternal(AuthenticationClientImpl client, long opId,
-            String opPackageName) {
-        final int callingUid = Binder.getCallingUid();
-        final int callingPid = Binder.getCallingPid();
-        final int callingUserId = UserHandle.getCallingUserId();
-        authenticateInternal(client, opId, opPackageName, callingUid, callingPid, callingUserId);
-    }
-
-    protected void authenticateInternal(AuthenticationClientImpl client, long opId,
-            String opPackageName, int callingUid, int callingPid, int callingUserId) {
-        if (!canUseBiometric(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
-                callingUserId)) {
-            if (DEBUG) Slog.v(getTag(), "authenticate(): reject " + opPackageName);
-            return;
-        }
-
-        mHandler.post(() -> {
-            mMetricsLogger.histogram(getMetrics().tagAuthToken(), opId != 0L ? 1 : 0);
-
-            // Get performance stats object for this user.
-            HashMap<Integer, PerformanceStats> pmap
-                    = (opId == 0) ? mPerformanceMap : mCryptoPerformanceMap;
-            PerformanceStats stats = pmap.get(mCurrentUserId);
-            if (stats == null) {
-                stats = new PerformanceStats();
-                pmap.put(mCurrentUserId, stats);
-            }
-            mPerformanceStats = stats;
-
-            startAuthentication(client, opPackageName);
-        });
-    }
-
-    protected void cancelAuthenticationInternal(final IBinder token, final String opPackageName) {
-        final int callingUid = Binder.getCallingUid();
-        final int callingPid = Binder.getCallingPid();
-        final int callingUserId = UserHandle.getCallingUserId();
-        cancelAuthenticationInternal(token, opPackageName, callingUid, callingPid, callingUserId);
-    }
-
-    protected void cancelAuthenticationInternal(final IBinder token, final String opPackageName,
-            int callingUid, int callingPid, int callingUserId) {
-        if (!canUseBiometric(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
-                callingUserId)) {
-            if (DEBUG) Slog.v(getTag(), "cancelAuthentication(): reject " + opPackageName);
-            return;
-        }
-
-        mHandler.post(() -> {
-            ClientMonitor client = mCurrentClient;
-            if (client instanceof AuthenticationClient) {
-                if (client.getToken() == token) {
-                    if (DEBUG) Slog.v(getTag(), "stop client " + client.getOwnerString());
-                    client.stop(client.getToken() == token);
-                } else {
-                    if (DEBUG) Slog.v(getTag(), "can't stop client "
-                            + client.getOwnerString() + " since tokens don't match");
-                }
-            } else if (client != null) {
-                if (DEBUG) Slog.v(getTag(), "can't cancel non-authenticating client "
-                        + client.getOwnerString());
-            }
-        });
-    }
-
-    protected void setActiveUserInternal(int userId) {
-        mHandler.post(() -> {
-            updateActiveGroup(userId, null /* clientPackage */);
-        });
-    }
-
-    protected void removeInternal(RemovalClientImpl client) {
-        mHandler.post(() -> {
-            startClient(client, true /* initiatedByClient */);
-        });
-    }
-
-    protected void enumerateInternal(EnumerateClientImpl client) {
-        mHandler.post(() -> {
-            startClient(client, true /* initiatedByClient */);
-        });
-    }
-
-    // Should be done on a handler thread - not on the Binder's thread.
-    private void startAuthentication(AuthenticationClientImpl client, String opPackageName) {
-        updateActiveGroup(client.getGroupId(), opPackageName);
-
-        if (DEBUG) Slog.v(getTag(), "startAuthentication(" + opPackageName + ")");
-
-        int lockoutMode = getLockoutMode();
-        if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
-            Slog.v(getTag(), "In lockout mode(" + lockoutMode +
-                    ") ; disallowing authentication");
-            int errorCode = lockoutMode == AuthenticationClient.LOCKOUT_TIMED ?
-                    BiometricConstants.BIOMETRIC_ERROR_LOCKOUT :
-                    BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
-            if (!client.onError(getHalDeviceId(), errorCode, 0 /* vendorCode */)) {
-                Slog.w(getTag(), "Cannot send permanent lockout message to client");
-            }
-            return;
-        }
-        startClient(client, true /* initiatedByClient */);
-    }
-
-    protected void addLockoutResetCallback(IBiometricServiceLockoutResetCallback callback) {
-        mHandler.post(() -> {
-           final LockoutResetMonitor monitor = new LockoutResetMonitor(callback);
-           if (!mLockoutMonitors.contains(monitor)) {
-               mLockoutMonitors.add(monitor);
-           }
-        });
-    }
-
-    /**
-     * Helper methods.
-     */
-
-    /**
-     * @param opPackageName name of package for caller
-     * @param requireForeground only allow this call while app is in the foreground
-     * @return true if caller can use the biometric API
-     */
-    protected boolean canUseBiometric(String opPackageName, boolean requireForeground, int uid,
-            int pid, int userId) {
-        checkUseBiometricPermission();
-
-        if (isKeyguard(opPackageName)) {
-            return true; // Keyguard is always allowed
-        }
-        if (!isCurrentUserOrProfile(userId)) {
-            Slog.w(getTag(), "Rejecting " + opPackageName + "; not a current user or profile");
-            return false;
-        }
-        if (mAppOps.noteOp(getAppOp(), uid, opPackageName) != AppOpsManager.MODE_ALLOWED) {
-            Slog.w(getTag(), "Rejecting " + opPackageName + "; permission denied");
-            return false;
-        }
-        if (requireForeground && !(isForegroundActivity(uid, pid) || isCurrentClient(
-                opPackageName))) {
-            Slog.w(getTag(), "Rejecting " + opPackageName + "; not in foreground");
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * @param opPackageName package of the caller
-     * @return true if this is the same client currently using the biometric
-     */
-    private boolean isCurrentClient(String opPackageName) {
-        return mCurrentClient != null && mCurrentClient.getOwnerString().equals(opPackageName);
-    }
-
-    /**
-     * @return true if this is keyguard package
-     */
-    private boolean isKeyguard(String clientPackage) {
-        return mKeyguardPackage.equals(clientPackage);
-    }
-
-    private int getLockoutMode() {
-        final int currentUser = ActivityManager.getCurrentUser();
-        final int failedAttempts = mFailedAttempts.get(currentUser, 0);
-        if (failedAttempts >= getFailedAttemptsLockoutPermanent()) {
-            return AuthenticationClient.LOCKOUT_PERMANENT;
-        } else if (failedAttempts > 0 &&
-                mTimedLockoutCleared.get(currentUser, false) == false
-                && (failedAttempts % getFailedAttemptsLockoutTimed() == 0)) {
-            return AuthenticationClient.LOCKOUT_TIMED;
-        }
-        return AuthenticationClient.LOCKOUT_NONE;
-    }
-
-    private boolean isForegroundActivity(int uid, int pid) {
-        try {
-            List<ActivityManager.RunningAppProcessInfo> procs =
-                    ActivityManager.getService().getRunningAppProcesses();
-            int N = procs.size();
-            for (int i = 0; i < N; i++) {
-                ActivityManager.RunningAppProcessInfo proc = procs.get(i);
-                if (proc.pid == pid && proc.uid == uid
-                        && proc.importance <= IMPORTANCE_FOREGROUND_SERVICE) {
-                    return true;
+        // Find first authenticator that's both detected and enrolled
+        boolean isHardwareDetected = false;
+        boolean hasTemplatesEnrolled = false;
+        for (int i = 0; i < mAuthenticators.size(); i++) {
+            int featureId = mAuthenticators.get(i).getType();
+            BiometricAuthenticator authenticator = mAuthenticators.get(i).getAuthenticator();
+            if (authenticator.isHardwareDetected()) {
+                isHardwareDetected = true;
+                if (authenticator.hasEnrolledTemplates()) {
+                    hasTemplatesEnrolled = true;
+                    modality = featureId;
+                    break;
                 }
             }
-        } catch (RemoteException e) {
-            Slog.w(getTag(), "am.getRunningAppProcesses() failed");
         }
-        return false;
-    }
 
-    /**
-     * Calls the HAL to switch states to the new task. If there's already a current task,
-     * it calls cancel() and sets mPendingClient to begin when the current task finishes
-     * ({@link BiometricConstants#BIOMETRIC_ERROR_CANCELED}).
-     *
-     * @param newClient the new client that wants to connect
-     * @param initiatedByClient true for authenticate, remove and enroll
-     */
-    private void startClient(ClientMonitor newClient, boolean initiatedByClient) {
-        ClientMonitor currentClient = mCurrentClient;
-        if (currentClient != null) {
-            if (DEBUG) Slog.v(getTag(), "request stop current client " +
-                    currentClient.getOwnerString());
-
-            // This check only matters for FingerprintService, since enumerate may call back
-            // multiple times.
-            if (currentClient instanceof FingerprintService.EnumerateClientImpl ||
-                    currentClient instanceof FingerprintService.RemovalClientImpl) {
-                // This condition means we're currently running internal diagnostics to
-                // remove extra fingerprints in the hardware and/or the software
-                // TODO: design an escape hatch in case client never finishes
-                if (newClient != null) {
-                    Slog.w(getTag(), "Internal cleanup in progress but trying to start client "
-                            + newClient.getClass().getSuperclass().getSimpleName()
-                            + "(" + newClient.getOwnerString() + ")"
-                            + ", initiatedByClient = " + initiatedByClient);
-                }
-            } else {
-                currentClient.stop(initiatedByClient);
+        // Check error conditions
+        if (!isHardwareDetected) {
+            try {
+                receiver.onError(0 /* deviceId */,
+                        BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
+                        hardwareUnavailable);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Unable to send error", e);
             }
-            mPendingClient = newClient;
-            mHandler.removeCallbacks(mResetClientState);
-            mHandler.postDelayed(mResetClientState, CANCEL_TIMEOUT_LIMIT);
-        } else if (newClient != null) {
-            mCurrentClient = newClient;
-            if (DEBUG) Slog.v(getTag(), "starting client "
-                    + newClient.getClass().getSuperclass().getSimpleName()
-                    + "(" + newClient.getOwnerString() + ")"
-                    + ", initiatedByClient = " + initiatedByClient);
-            notifyClientActiveCallbacks(true);
-
-            newClient.start();
+            return BIOMETRIC_NONE;
         }
-    }
-
-    protected void removeClient(ClientMonitor client) {
-        if (client != null) {
-            client.destroy();
-            if (client != mCurrentClient && mCurrentClient != null) {
-                Slog.w(getTag(), "Unexpected client: " + client.getOwnerString() + "expected: "
-                        + mCurrentClient.getOwnerString());
+        if (!hasTemplatesEnrolled) {
+            try {
+                receiver.onError(0 /* deviceId */,
+                        BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS,
+                        FaceManager.getErrorString(getContext(),
+                                BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS,
+                                0 /* vendorCode */));
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Unable to send error", e);
             }
+            return BIOMETRIC_NONE;
         }
-        if (mCurrentClient != null) {
-            if (DEBUG) Slog.v(getTag(), "Done with client: " + client.getOwnerString());
-            mCurrentClient = null;
-        }
-        if (mPendingClient == null) {
-            notifyClientActiveCallbacks(false);
+
+        return modality;
+    }
+
+    private BiometricAuthenticator getAuthenticator(int type) {
+        switch (type) {
+            case BIOMETRIC_FINGERPRINT:
+                return (FingerprintManager)
+                        getContext().getSystemService(Context.FINGERPRINT_SERVICE);
+            case BIOMETRIC_IRIS:
+                return null;
+            case BIOMETRIC_FACE:
+                return (FaceManager)
+                        getContext().getSystemService(Context.FACE_SERVICE);
+            default:
+                return null;
         }
     }
 
-    /**
-     * Populates existing authenticator ids. To be used only during the start of the service.
-     */
-    protected void loadAuthenticatorIds() {
-        // This operation can be expensive, so keep track of the elapsed time. Might need to move to
-        // background if it takes too long.
-        long t = System.currentTimeMillis();
-        mAuthenticatorIds.clear();
-        for (UserInfo user : UserManager.get(getContext()).getUsers(true /* excludeDying */)) {
-            int userId = getUserOrWorkProfileId(null, user.id);
-            if (!mAuthenticatorIds.containsKey(userId)) {
-                updateActiveGroup(userId, null);
-            }
-        }
-
-        t = System.currentTimeMillis() - t;
-        if (t > 1000) {
-            Slog.w(getTag(), "loadAuthenticatorIds() taking too long: " + t + "ms");
+    private boolean hasFeature(int type) {
+        switch (type) {
+            case BIOMETRIC_FINGERPRINT:
+                return mHasFeatureFingerprint;
+            case BIOMETRIC_IRIS:
+                return mHasFeatureIris;
+            case BIOMETRIC_FACE:
+                return mHasFeatureFace;
+            default:
+                return false;
         }
     }
-
-    /**
-     * @param clientPackage the package of the caller
-     * @return the profile id
-     */
-    protected int getUserOrWorkProfileId(String clientPackage, int userId) {
-        if (!isKeyguard(clientPackage) && isWorkProfile(userId)) {
-            return userId;
-        }
-        return getEffectiveUserId(userId);
-    }
-
-    protected boolean isRestricted() {
-        // Only give privileged apps (like Settings) access to biometric info
-        final boolean restricted = !hasPermission(getManageBiometricPermission());
-        return restricted;
-    }
-
-    protected boolean hasPermission(String permission) {
-        return getContext().checkCallingOrSelfPermission(permission)
-                == PackageManager.PERMISSION_GRANTED;
-    }
-
-    protected void checkPermission(String permission) {
-        getContext().enforceCallingOrSelfPermission(permission,
-                "Must have " + permission + " permission.");
-    }
-
-    protected boolean isCurrentUserOrProfile(int userId) {
-        UserManager um = UserManager.get(mContext);
-        if (um == null) {
-            Slog.e(getTag(), "Unable to acquire UserManager");
-            return false;
-        }
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            // Allow current user or profiles of the current user...
-            for (int profileId : um.getEnabledProfileIds(ActivityManager.getCurrentUser())) {
-                if (profileId == userId) {
-                    return true;
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-
-        return false;
-    }
-
-    /***
-     * @param opPackageName the name of the calling package
-     * @return authenticator id for the calling user
-     */
-    protected long getAuthenticatorId(String opPackageName) {
-        final int userId = getUserOrWorkProfileId(opPackageName, UserHandle.getCallingUserId());
-        return mAuthenticatorIds.getOrDefault(userId, 0L);
-    }
-
-    private void scheduleLockoutResetForUser(int userId) {
-        mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
-                SystemClock.elapsedRealtime() + FAIL_LOCKOUT_TIMEOUT_MS,
-                getLockoutResetIntentForUser(userId));
-    }
-
-    private PendingIntent getLockoutResetIntentForUser(int userId) {
-        return PendingIntent.getBroadcast(mContext, userId,
-                new Intent(getLockoutResetIntent()).putExtra(KEY_LOCKOUT_RESET_USER, userId),
-                PendingIntent.FLAG_UPDATE_CURRENT);
-    }
-
-    private void userActivity() {
-        long now = SystemClock.uptimeMillis();
-        mPowerManager.userActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
-    }
-
-    /**
-     * @param userId
-     * @return true if this is a work profile
-     */
-    private boolean isWorkProfile(int userId) {
-        UserInfo userInfo = null;
-        final long token = Binder.clearCallingIdentity();
-        try {
-            userInfo = mUserManager.getUserInfo(userId);
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-        return userInfo != null && userInfo.isManagedProfile();
-    }
-
-
-    private int getEffectiveUserId(int userId) {
-        UserManager um = UserManager.get(mContext);
-        if (um != null) {
-            final long callingIdentity = Binder.clearCallingIdentity();
-            userId = um.getCredentialOwnerProfile(userId);
-            Binder.restoreCallingIdentity(callingIdentity);
-        } else {
-            Slog.e(getTag(), "Unable to acquire UserManager");
-        }
-        return userId;
-    }
-
-    // Attempt counter should only be cleared when Keyguard goes away or when
-    // a biometric is successfully authenticated.
-    private void resetFailedAttemptsForUser(boolean clearAttemptCounter, int userId) {
-        if (DEBUG && getLockoutMode() != AuthenticationClient.LOCKOUT_NONE) {
-            Slog.v(getTag(), "Reset biometric lockout, clearAttemptCounter=" + clearAttemptCounter);
-        }
-        if (clearAttemptCounter) {
-            mFailedAttempts.put(userId, 0);
-        }
-        mTimedLockoutCleared.put(userId, true);
-        // If we're asked to reset failed attempts externally (i.e. from Keyguard),
-        // the alarm might still be pending; remove it.
-        cancelLockoutResetForUser(userId);
-        notifyLockoutResetMonitors();
-    }
-
-    private void cancelLockoutResetForUser(int userId) {
-        mAlarmManager.cancel(getLockoutResetIntentForUser(userId));
-    }
-
-    private void listenForUserSwitches() {
-        try {
-            ActivityManager.getService().registerUserSwitchObserver(
-                    new SynchronousUserSwitchObserver() {
-                        @Override
-                        public void onUserSwitching(int newUserId) throws RemoteException {
-                            mHandler.obtainMessage(MSG_USER_SWITCHING, newUserId, 0 /* unused */)
-                                    .sendToTarget();
-                        }
-                    }, getTag());
-        } catch (RemoteException e) {
-            Slog.w(getTag(), "Failed to listen for user switching event" ,e);
-        }
-    }
-
-    private void notifyLockoutResetMonitors() {
-        for (int i = 0; i < mLockoutMonitors.size(); i++) {
-            mLockoutMonitors.get(i).sendLockoutReset();
-        }
-    }
-
-    private void removeLockoutResetCallback(
-            LockoutResetMonitor monitor) {
-        mLockoutMonitors.remove(monitor);
-    }
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
new file mode 100644
index 0000000..6a22193
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -0,0 +1,1113 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics;
+
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
+
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.app.AlarmManager;
+import android.app.AppOpsManager;
+import android.app.IActivityTaskManager;
+import android.app.PendingIntent;
+import android.app.SynchronousUserSwitchObserver;
+import android.app.TaskStackListener;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.IBiometricPromptReceiver;
+import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
+import android.hardware.fingerprint.Fingerprint;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.DeadObjectException;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IHwBinder;
+import android.os.IRemoteCallback;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Slog;
+import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.server.SystemService;
+import com.android.server.biometrics.fingerprint.FingerprintService;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Abstract base class containing all of the business logic for biometric services, e.g.
+ * Fingerprint, Face, Iris.
+ *
+ * @hide
+ */
+public abstract class BiometricServiceBase extends SystemService
+        implements IHwBinder.DeathRecipient {
+
+    protected static final boolean DEBUG = true;
+
+    private static final String KEY_LOCKOUT_RESET_USER = "lockout_reset_user";
+    private static final int MSG_USER_SWITCHING = 10;
+    private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30 * 1000;
+    private static final long CANCEL_TIMEOUT_LIMIT = 3000; // max wait for onCancel() from HAL,in ms
+
+    private final Context mContext;
+    private final String mKeyguardPackage;
+    private final SparseBooleanArray mTimedLockoutCleared;
+    private final SparseIntArray mFailedAttempts;
+    private final IActivityTaskManager mActivityTaskManager;
+    private final AlarmManager mAlarmManager;
+    private final PowerManager mPowerManager;
+    private final UserManager mUserManager;
+    private final MetricsLogger mMetricsLogger;
+    private final BiometricTaskStackListener mTaskStackListener = new BiometricTaskStackListener();
+    private final ResetClientStateRunnable mResetClientState = new ResetClientStateRunnable();
+    private final LockoutReceiver mLockoutReceiver = new LockoutReceiver();
+    private final ArrayList<LockoutResetMonitor> mLockoutMonitors = new ArrayList<>();
+
+    protected final IStatusBarService mStatusBarService;
+    protected final Map<Integer, Long> mAuthenticatorIds =
+            Collections.synchronizedMap(new HashMap<>());
+    protected final ResetFailedAttemptsForUserRunnable mResetFailedAttemptsForCurrentUserRunnable =
+            new ResetFailedAttemptsForUserRunnable();
+    protected final AppOpsManager mAppOps;
+    protected final H mHandler = new H();
+
+    private ClientMonitor mCurrentClient;
+    private ClientMonitor mPendingClient;
+    private PerformanceStats mPerformanceStats;
+    protected int mCurrentUserId = UserHandle.USER_NULL;
+    // Tracks if the current authentication makes use of CryptoObjects.
+    protected boolean mIsCrypto;
+    // Normal authentications are tracked by mPerformanceMap.
+    protected HashMap<Integer, PerformanceStats> mPerformanceMap = new HashMap<>();
+    // Transactions that make use of CryptoObjects are tracked by mCryptoPerformaceMap.
+    protected HashMap<Integer, PerformanceStats> mCryptoPerformanceMap = new HashMap<>();
+
+    protected class PerformanceStats {
+        public int accept; // number of accepted biometrics
+        public int reject; // number of rejected biometrics
+        public int acquire; // total number of acquisitions. Should be >= accept+reject due to poor
+        // image acquisition in some cases (too fast, too slow, dirty sensor, etc.)
+        public int lockout; // total number of lockouts
+        public int permanentLockout; // total number of permanent lockouts
+    }
+
+    /**
+     * @return the log tag.
+     */
+    protected abstract String getTag();
+
+    /**
+     * @return the biometric utilities for a specific implementation.
+     */
+    protected abstract BiometricUtils getBiometricUtils();
+
+    /**
+     * @return the number of failed attempts after which the user will be temporarily locked out
+     *         from using the biometric. A strong auth (pin/pattern/pass) clears this counter.
+     */
+    protected abstract int getFailedAttemptsLockoutTimed();
+
+    /**
+     * @return the number of failed attempts after which the user will be permanently locked out
+     *         from using the biometric. A strong auth (pin/pattern/pass) clears this counter.
+     */
+    protected abstract int getFailedAttemptsLockoutPermanent();
+
+    /**
+     * @return the metrics constants for a biometric implementation.
+     */
+    protected abstract Metrics getMetrics();
+
+    /**
+     * @param userId
+     * @return true if the enrollment limit has been reached.
+     */
+    protected abstract boolean hasReachedEnrollmentLimit(int userId);
+
+    /**
+     * Notifies the HAL that the user has changed.
+     * @param userId
+     * @param clientPackage
+     */
+    protected abstract void updateActiveGroup(int userId, String clientPackage);
+
+    /**
+     * @return The protected intent to reset lockout for a specific biometric.
+     */
+    protected abstract String getLockoutResetIntent();
+
+    /**
+     * @return The permission the sender is required to have in order for the lockout reset intent
+     *         to be received by the BiometricService implementation.
+     */
+    protected abstract String getLockoutBroadcastPermission();
+
+    /**
+     * @return The HAL ID.
+     */
+    protected abstract long getHalDeviceId();
+
+    /**
+     * This method is called when the user switches. Implementations should probably notify the
+     * HAL.
+     * @param userId
+     */
+    protected abstract void handleUserSwitching(int userId);
+
+    /**
+     * @param userId
+     * @return Returns true if the user has any enrolled biometrics.
+     */
+    protected abstract boolean hasEnrolledBiometrics(int userId);
+
+    /**
+     * @return Returns the MANAGE_* permission string, which is required for enrollment, removal
+     * etc.
+     */
+    protected abstract String getManageBiometricPermission();
+
+    /**
+     * Checks if the caller has permission to use the biometric service - throws a SecurityException
+     * if not.
+     */
+    protected abstract void checkUseBiometricPermission();
+
+    /**
+     * Checks if the caller passes the app ops check
+     */
+    protected abstract boolean checkAppOps(int uid, String opPackageName);
+
+    /**
+     * Notifies clients of any change in the biometric state (active / idle). This is mainly for
+     * Fingerprint navigation gestures.
+     * @param isActive
+     */
+    protected void notifyClientActiveCallbacks(boolean isActive) {}
+
+    protected abstract class AuthenticationClientImpl extends AuthenticationClient {
+
+        public AuthenticationClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
+                IBinder token, ServiceListener listener, int targetUserId, int groupId, long opId,
+                boolean restricted, String owner, Bundle bundle,
+                IBiometricPromptReceiver dialogReceiver,
+                IStatusBarService statusBarService, boolean requireConfirmation) {
+            super(context, getMetrics(), daemon, halDeviceId, token, listener,
+                    targetUserId, groupId, opId, restricted, owner, bundle, dialogReceiver,
+                    statusBarService, requireConfirmation);
+        }
+
+        @Override
+        public void onStart() {
+            try {
+                mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
+            } catch (RemoteException e) {
+                Slog.e(getTag(), "Could not register task stack listener", e);
+            }
+        }
+
+        @Override
+        public void onStop() {
+            try {
+                mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
+            } catch (RemoteException e) {
+                Slog.e(getTag(), "Could not unregister task stack listener", e);
+            }
+        }
+
+        @Override
+        public void resetFailedAttempts() {
+            resetFailedAttemptsForUser(true /* clearAttemptCounter */,
+                    ActivityManager.getCurrentUser());
+        }
+
+        @Override
+        public void notifyUserActivity() {
+            userActivity();
+        }
+
+        @Override
+        public int handleFailedAttempt() {
+            final int currentUser = ActivityManager.getCurrentUser();
+            mFailedAttempts.put(currentUser, mFailedAttempts.get(currentUser, 0) + 1);
+            mTimedLockoutCleared.put(ActivityManager.getCurrentUser(), false);
+            final int lockoutMode = getLockoutMode();
+            if (lockoutMode == AuthenticationClient.LOCKOUT_PERMANENT) {
+                mPerformanceStats.permanentLockout++;
+            } else if (lockoutMode == AuthenticationClient.LOCKOUT_TIMED) {
+                mPerformanceStats.lockout++;
+            }
+
+            // Failing multiple times will continue to push out the lockout time
+            if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
+                scheduleLockoutResetForUser(currentUser);
+                return lockoutMode;
+            }
+            return AuthenticationClient.LOCKOUT_NONE;
+        }
+
+        @Override
+        public void onAuthenticationConfirmed() {
+            removeClient(mCurrentClient);
+        }
+    }
+
+    protected class EnrollClientImpl extends EnrollClient {
+
+        public EnrollClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
+                IBinder token, ServiceListener listener, int userId, int groupId,
+                byte[] cryptoToken, boolean restricted, String owner) {
+            super(context, getMetrics(), daemon, halDeviceId, token, listener,
+                    userId, groupId, cryptoToken, restricted, owner, getBiometricUtils());
+        }
+
+        @Override
+        public void notifyUserActivity() {
+            userActivity();
+        }
+    }
+
+    protected class RemovalClientImpl extends RemovalClient {
+        private boolean mShouldNotify;
+
+        public RemovalClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
+                IBinder token, ServiceListener listener, int fingerId, int groupId, int userId,
+                boolean restricted, String owner) {
+            super(context, getMetrics(), daemon, halDeviceId, token, listener, fingerId, groupId,
+                    userId, restricted, owner, getBiometricUtils());
+        }
+
+        public void setShouldNotifyUserActivity(boolean shouldNotify) {
+            mShouldNotify = shouldNotify;
+        }
+
+        @Override
+        public void notifyUserActivity() {
+            if (mShouldNotify) {
+                userActivity();
+            }
+        }
+    }
+
+    protected class EnumerateClientImpl extends EnumerateClient {
+
+        public EnumerateClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
+                IBinder token, ServiceListener listener, int groupId, int userId,
+                boolean restricted, String owner) {
+            super(context, getMetrics(), daemon, halDeviceId, token, listener, groupId, userId,
+                    restricted, owner);
+        }
+
+        @Override
+        public void notifyUserActivity() {
+            userActivity();
+        }
+    }
+
+    /**
+     * Wraps the callback interface from Service -> Manager
+     */
+    protected interface ServiceListener {
+        default void onEnrollResult(BiometricAuthenticator.Identifier identifier,
+                int remaining) throws RemoteException {};
+
+        void onAcquired(long deviceId, int acquiredInfo, int vendorCode)
+                throws RemoteException;
+
+        void onAuthenticationSucceeded(long deviceId,
+                BiometricAuthenticator.Identifier biometric, int userId)
+                throws RemoteException;
+
+        void onAuthenticationFailed(long deviceId)
+                throws RemoteException;
+
+        void onError(long deviceId, int error, int vendorCode)
+                throws RemoteException;
+
+        default void onRemoved(BiometricAuthenticator.Identifier identifier,
+                int remaining) throws RemoteException {};
+
+        default void onEnumerated(BiometricAuthenticator.Identifier identifier,
+                int remaining) throws RemoteException {};
+    }
+
+    /**
+     * Wraps a portion of the interface from Service -> Daemon that is used by the ClientMonitor
+     * subclasses.
+     */
+    protected interface DaemonWrapper {
+        int ERROR_ESRCH = 3; // Likely fingerprint HAL is dead. see errno.h.
+        int authenticate(long operationId, int groupId) throws RemoteException;
+        int cancel() throws RemoteException;
+        int remove(int groupId, int biometricId) throws RemoteException;
+        int enumerate() throws RemoteException;
+        int enroll(byte[] cryptoToken, int groupId, int timeout) throws RemoteException;
+    }
+
+    /**
+     * Handler which all subclasses should post events to.
+     */
+    protected final class H extends Handler {
+        @Override
+        public void handleMessage(android.os.Message msg) {
+            switch (msg.what) {
+                case MSG_USER_SWITCHING:
+                    handleUserSwitching(msg.arg1);
+                    break;
+
+                default:
+                    Slog.w(getTag(), "Unknown message:" + msg.what);
+            }
+        }
+    }
+
+    private final class BiometricTaskStackListener extends TaskStackListener {
+        @Override
+        public void onTaskStackChanged() {
+            try {
+                if (!(mCurrentClient instanceof AuthenticationClient)) {
+                    return;
+                }
+                final String currentClient = mCurrentClient.getOwnerString();
+                if (isKeyguard(currentClient)) {
+                    return; // Keyguard is always allowed
+                }
+                List<ActivityManager.RunningTaskInfo> runningTasks =
+                        mActivityTaskManager.getTasks(1);
+                if (!runningTasks.isEmpty()) {
+                    final String topPackage = runningTasks.get(0).topActivity.getPackageName();
+                    if (!topPackage.contentEquals(currentClient)) {
+                        Slog.e(getTag(), "Stopping background authentication, top: " + topPackage
+                                + " currentClient: " + currentClient);
+                        mCurrentClient.stop(false /* initiatedByClient */);
+                    }
+                }
+            } catch (RemoteException e) {
+                Slog.e(getTag(), "Unable to get running tasks", e);
+            }
+        }
+    }
+
+    private final class ResetClientStateRunnable implements Runnable {
+        @Override
+        public void run() {
+            /**
+             * Warning: if we get here, the driver never confirmed our call to cancel the current
+             * operation (authenticate, enroll, remove, enumerate, etc), which is
+             * really bad.  The result will be a 3-second delay in starting each new client.
+             * If you see this on a device, make certain the driver notifies with
+             * {@link BiometricConstants#BIOMETRIC_ERROR_CANCELED} in response to cancel()
+             * once it has successfully switched to the IDLE state in the HAL.
+             * Additionally,{@link BiometricConstants#BIOMETRIC_ERROR_CANCELED} should only be sent
+             * in response to an actual cancel() call.
+             */
+            Slog.w(getTag(), "Client "
+                    + (mCurrentClient != null ? mCurrentClient.getOwnerString() : "null")
+                    + " failed to respond to cancel, starting client "
+                    + (mPendingClient != null ? mPendingClient.getOwnerString() : "null"));
+
+            mCurrentClient = null;
+            startClient(mPendingClient, false);
+        }
+    }
+
+    private final class LockoutReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            Slog.v(getTag(), "Resetting lockout: " + intent.getAction());
+            if (getLockoutResetIntent().equals(intent.getAction())) {
+                final int user = intent.getIntExtra(KEY_LOCKOUT_RESET_USER, 0);
+                resetFailedAttemptsForUser(false /* clearAttemptCounter */, user);
+            }
+        }
+    }
+
+    private final class ResetFailedAttemptsForUserRunnable implements Runnable {
+        @Override
+        public void run() {
+            resetFailedAttemptsForUser(true /* clearAttemptCounter */,
+                    ActivityManager.getCurrentUser());
+        }
+    }
+
+    private final class LockoutResetMonitor implements IBinder.DeathRecipient {
+        private static final long WAKELOCK_TIMEOUT_MS = 2000;
+        private final IBiometricServiceLockoutResetCallback mCallback;
+        private final PowerManager.WakeLock mWakeLock;
+
+        public LockoutResetMonitor(IBiometricServiceLockoutResetCallback callback) {
+            mCallback = callback;
+            mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+                    "lockout reset callback");
+            try {
+                mCallback.asBinder().linkToDeath(LockoutResetMonitor.this, 0);
+            } catch (RemoteException e) {
+                Slog.w(getTag(), "caught remote exception in linkToDeath", e);
+            }
+        }
+
+        public void sendLockoutReset() {
+            if (mCallback != null) {
+                try {
+                    mWakeLock.acquire(WAKELOCK_TIMEOUT_MS);
+                    mCallback.onLockoutReset(getHalDeviceId(), new IRemoteCallback.Stub() {
+                        @Override
+                        public void sendResult(Bundle data) throws RemoteException {
+                            releaseWakelock();
+                        }
+                    });
+                } catch (DeadObjectException e) {
+                    Slog.w(getTag(), "Death object while invoking onLockoutReset: ", e);
+                    mHandler.post(mRemoveCallbackRunnable);
+                } catch (RemoteException e) {
+                    Slog.w(getTag(), "Failed to invoke onLockoutReset: ", e);
+                    releaseWakelock();
+                }
+            }
+        }
+
+        private final Runnable mRemoveCallbackRunnable = new Runnable() {
+            @Override
+            public void run() {
+                releaseWakelock();
+                removeLockoutResetCallback(LockoutResetMonitor.this);
+            }
+        };
+
+        @Override
+        public void binderDied() {
+            Slog.e(getTag(), "Lockout reset callback binder died");
+            mHandler.post(mRemoveCallbackRunnable);
+        }
+
+        private void releaseWakelock() {
+            if (mWakeLock.isHeld()) {
+                mWakeLock.release();
+            }
+        }
+    }
+
+    /**
+     * Initializes the system service.
+     * <p>
+     * Subclasses must define a single argument constructor that accepts the context
+     * and passes it to super.
+     * </p>
+     *
+     * @param context The system server context.
+     */
+    public BiometricServiceBase(Context context) {
+        super(context);
+        mContext = context;
+        mStatusBarService = IStatusBarService.Stub.asInterface(
+                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+        mKeyguardPackage = ComponentName.unflattenFromString(context.getResources().getString(
+                com.android.internal.R.string.config_keyguardComponent)).getPackageName();
+        mAppOps = context.getSystemService(AppOpsManager.class);
+        mTimedLockoutCleared = new SparseBooleanArray();
+        mFailedAttempts = new SparseIntArray();
+        mActivityTaskManager = ((ActivityTaskManager) context.getSystemService(
+                Context.ACTIVITY_TASK_SERVICE)).getService();
+        mPowerManager = mContext.getSystemService(PowerManager.class);
+        mAlarmManager = mContext.getSystemService(AlarmManager.class);
+        mUserManager = UserManager.get(mContext);
+        mMetricsLogger = new MetricsLogger();
+        mContext.registerReceiver(mLockoutReceiver, new IntentFilter(getLockoutResetIntent()),
+                getLockoutBroadcastPermission(), null /* handler */);
+    }
+
+    @Override
+    public void onStart() {
+        listenForUserSwitches();
+    }
+
+    @Override
+    public void serviceDied(long cookie) {
+        Slog.e(getTag(), "HAL died");
+        mMetricsLogger.count(getMetrics().tagHalDied(), 1);
+        handleError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
+                0 /*vendorCode */);
+    }
+
+    protected ClientMonitor getCurrentClient() {
+        return mCurrentClient;
+    }
+
+    protected ClientMonitor getPendingClient() {
+        return mPendingClient;
+    }
+
+    /**
+     * Callback handlers from the daemon. The caller must put this on a handler.
+     */
+
+    protected void handleAcquired(long deviceId, int acquiredInfo, int vendorCode) {
+        ClientMonitor client = mCurrentClient;
+        if (client != null && client.onAcquired(acquiredInfo, vendorCode)) {
+            removeClient(client);
+        }
+        if (mPerformanceStats != null && getLockoutMode() == AuthenticationClient.LOCKOUT_NONE
+                && client instanceof AuthenticationClient) {
+            // ignore enrollment acquisitions or acquisitions when we're locked out
+            mPerformanceStats.acquire++;
+        }
+    }
+
+    protected void handleAuthenticated(BiometricAuthenticator.Identifier identifier,
+            ArrayList<Byte> token) {
+        ClientMonitor client = mCurrentClient;
+        final boolean authenticated = identifier.getBiometricId() != 0;
+
+        if (client != null && client.onAuthenticated(identifier, authenticated, token)) {
+            removeClient(client);
+        }
+        if (authenticated) {
+            mPerformanceStats.accept++;
+        } else {
+            mPerformanceStats.reject++;
+        }
+    }
+
+    protected void handleEnrollResult(BiometricAuthenticator.Identifier identifier,
+            int remaining) {
+        ClientMonitor client = mCurrentClient;
+        if (client != null && client.onEnrollResult(identifier, remaining)) {
+            removeClient(client);
+            // When enrollment finishes, update this group's authenticator id, as the HAL has
+            // already generated a new authenticator id when the new biometric is enrolled.
+            if (identifier instanceof Fingerprint) {
+                updateActiveGroup(((Fingerprint)identifier).getGroupId(), null);
+            } else {
+                updateActiveGroup(mCurrentUserId, null);
+            }
+
+        }
+    }
+
+    protected void handleError(long deviceId, int error, int vendorCode) {
+        final ClientMonitor client = mCurrentClient;
+
+        if (DEBUG) Slog.v(getTag(), "handleError(client="
+                + (client != null ? client.getOwnerString() : "null") + ", error = " + error + ")");
+
+        if (client != null && client.onError(deviceId, error, vendorCode)) {
+            removeClient(client);
+        }
+
+        if (error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) {
+            mHandler.removeCallbacks(mResetClientState);
+            if (mPendingClient != null) {
+                if (DEBUG) Slog.v(getTag(), "start pending client " +
+                        mPendingClient.getOwnerString());
+                startClient(mPendingClient, false);
+                mPendingClient = null;
+            }
+        }
+    }
+
+    protected void handleRemoved(BiometricAuthenticator.Identifier identifier,
+            final int remaining) {
+        if (DEBUG) Slog.w(getTag(), "Removed: fid=" + identifier.getBiometricId()
+                + ", dev=" + identifier.getDeviceId()
+                + ", rem=" + remaining);
+
+        ClientMonitor client = mCurrentClient;
+        if (client != null && client.onRemoved(identifier, remaining)) {
+            removeClient(client);
+            // When the last biometric of a group is removed, update the authenticator id
+            int userId = mCurrentUserId;
+            if (identifier instanceof Fingerprint) {
+                userId = ((Fingerprint) identifier).getGroupId();
+            }
+            if (!hasEnrolledBiometrics(userId)) {
+                updateActiveGroup(userId, null);
+            }
+        }
+    }
+
+    /**
+     * Calls from the Manager. These are still on the calling binder's thread.
+     */
+
+    protected void enrollInternal(EnrollClientImpl client, int userId) {
+        if (hasReachedEnrollmentLimit(userId)) {
+            return;
+        }
+
+        // Group ID is arbitrarily set to parent profile user ID. It just represents
+        // the default biometrics for the user.
+        if (!isCurrentUserOrProfile(userId)) {
+            return;
+        }
+
+        mHandler.post(() -> {
+            startClient(client, true /* initiatedByClient */);
+        });
+    }
+
+    protected void cancelEnrollmentInternal(IBinder token) {
+        mHandler.post(() -> {
+            ClientMonitor client = mCurrentClient;
+            if (client instanceof EnrollClient && client.getToken() == token) {
+                client.stop(client.getToken() == token);
+            }
+        });
+    }
+
+    protected void authenticateInternal(AuthenticationClientImpl client, long opId,
+            String opPackageName) {
+        final int callingUid = Binder.getCallingUid();
+        final int callingPid = Binder.getCallingPid();
+        final int callingUserId = UserHandle.getCallingUserId();
+        authenticateInternal(client, opId, opPackageName, callingUid, callingPid, callingUserId);
+    }
+
+    protected void authenticateInternal(AuthenticationClientImpl client, long opId,
+            String opPackageName, int callingUid, int callingPid, int callingUserId) {
+        if (!canUseBiometric(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
+                callingUserId)) {
+            if (DEBUG) Slog.v(getTag(), "authenticate(): reject " + opPackageName);
+            return;
+        }
+
+        mHandler.post(() -> {
+            mMetricsLogger.histogram(getMetrics().tagAuthToken(), opId != 0L ? 1 : 0);
+
+            // Get performance stats object for this user.
+            HashMap<Integer, PerformanceStats> pmap
+                    = (opId == 0) ? mPerformanceMap : mCryptoPerformanceMap;
+            PerformanceStats stats = pmap.get(mCurrentUserId);
+            if (stats == null) {
+                stats = new PerformanceStats();
+                pmap.put(mCurrentUserId, stats);
+            }
+            mPerformanceStats = stats;
+            mIsCrypto = (opId != 0);
+
+            startAuthentication(client, opPackageName);
+        });
+    }
+
+    protected void cancelAuthenticationInternal(final IBinder token, final String opPackageName) {
+        final int callingUid = Binder.getCallingUid();
+        final int callingPid = Binder.getCallingPid();
+        final int callingUserId = UserHandle.getCallingUserId();
+        cancelAuthenticationInternal(token, opPackageName, callingUid, callingPid, callingUserId);
+    }
+
+    protected void cancelAuthenticationInternal(final IBinder token, final String opPackageName,
+            int callingUid, int callingPid, int callingUserId) {
+        if (!canUseBiometric(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
+                callingUserId)) {
+            if (DEBUG) Slog.v(getTag(), "cancelAuthentication(): reject " + opPackageName);
+            return;
+        }
+
+        mHandler.post(() -> {
+            ClientMonitor client = mCurrentClient;
+            if (client instanceof AuthenticationClient) {
+                if (client.getToken() == token) {
+                    if (DEBUG) Slog.v(getTag(), "stop client " + client.getOwnerString());
+                    client.stop(client.getToken() == token);
+                } else {
+                    if (DEBUG) Slog.v(getTag(), "can't stop client "
+                            + client.getOwnerString() + " since tokens don't match");
+                }
+            } else if (client != null) {
+                if (DEBUG) Slog.v(getTag(), "can't cancel non-authenticating client "
+                        + client.getOwnerString());
+            }
+        });
+    }
+
+    protected void setActiveUserInternal(int userId) {
+        mHandler.post(() -> {
+            updateActiveGroup(userId, null /* clientPackage */);
+        });
+    }
+
+    protected void removeInternal(RemovalClientImpl client) {
+        mHandler.post(() -> {
+            startClient(client, true /* initiatedByClient */);
+        });
+    }
+
+    protected void enumerateInternal(EnumerateClientImpl client) {
+        mHandler.post(() -> {
+            startClient(client, true /* initiatedByClient */);
+        });
+    }
+
+    // Should be done on a handler thread - not on the Binder's thread.
+    private void startAuthentication(AuthenticationClientImpl client, String opPackageName) {
+        updateActiveGroup(client.getGroupId(), opPackageName);
+
+        if (DEBUG) Slog.v(getTag(), "startAuthentication(" + opPackageName + ")");
+
+        int lockoutMode = getLockoutMode();
+        if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
+            Slog.v(getTag(), "In lockout mode(" + lockoutMode +
+                    ") ; disallowing authentication");
+            int errorCode = lockoutMode == AuthenticationClient.LOCKOUT_TIMED ?
+                    BiometricConstants.BIOMETRIC_ERROR_LOCKOUT :
+                    BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
+            if (!client.onError(getHalDeviceId(), errorCode, 0 /* vendorCode */)) {
+                Slog.w(getTag(), "Cannot send permanent lockout message to client");
+            }
+            return;
+        }
+        startClient(client, true /* initiatedByClient */);
+    }
+
+    protected void addLockoutResetCallback(IBiometricServiceLockoutResetCallback callback) {
+        mHandler.post(() -> {
+           final LockoutResetMonitor monitor = new LockoutResetMonitor(callback);
+           if (!mLockoutMonitors.contains(monitor)) {
+               mLockoutMonitors.add(monitor);
+           }
+        });
+    }
+
+    /**
+     * Helper methods.
+     */
+
+    /**
+     * @param opPackageName name of package for caller
+     * @param requireForeground only allow this call while app is in the foreground
+     * @return true if caller can use the biometric API
+     */
+    protected boolean canUseBiometric(String opPackageName, boolean requireForeground, int uid,
+            int pid, int userId) {
+        checkUseBiometricPermission();
+
+        if (isKeyguard(opPackageName)) {
+            return true; // Keyguard is always allowed
+        }
+        if (!isCurrentUserOrProfile(userId)) {
+            Slog.w(getTag(), "Rejecting " + opPackageName + "; not a current user or profile");
+            return false;
+        }
+        if (!checkAppOps(uid, opPackageName)) {
+            Slog.w(getTag(), "Rejecting " + opPackageName + "; permission denied");
+            return false;
+        }
+
+        if (requireForeground && !(isForegroundActivity(uid, pid) || isCurrentClient(
+                opPackageName))) {
+            Slog.w(getTag(), "Rejecting " + opPackageName + "; not in foreground");
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * @param opPackageName package of the caller
+     * @return true if this is the same client currently using the biometric
+     */
+    private boolean isCurrentClient(String opPackageName) {
+        return mCurrentClient != null && mCurrentClient.getOwnerString().equals(opPackageName);
+    }
+
+    /**
+     * @return true if this is keyguard package
+     */
+    private boolean isKeyguard(String clientPackage) {
+        return mKeyguardPackage.equals(clientPackage);
+    }
+
+    protected int getLockoutMode() {
+        final int currentUser = ActivityManager.getCurrentUser();
+        final int failedAttempts = mFailedAttempts.get(currentUser, 0);
+        if (failedAttempts >= getFailedAttemptsLockoutPermanent()) {
+            return AuthenticationClient.LOCKOUT_PERMANENT;
+        } else if (failedAttempts > 0 &&
+                mTimedLockoutCleared.get(currentUser, false) == false
+                && (failedAttempts % getFailedAttemptsLockoutTimed() == 0)) {
+            return AuthenticationClient.LOCKOUT_TIMED;
+        }
+        return AuthenticationClient.LOCKOUT_NONE;
+    }
+
+    private boolean isForegroundActivity(int uid, int pid) {
+        try {
+            List<ActivityManager.RunningAppProcessInfo> procs =
+                    ActivityManager.getService().getRunningAppProcesses();
+            int N = procs.size();
+            for (int i = 0; i < N; i++) {
+                ActivityManager.RunningAppProcessInfo proc = procs.get(i);
+                if (proc.pid == pid && proc.uid == uid
+                        && proc.importance <= IMPORTANCE_FOREGROUND_SERVICE) {
+                    return true;
+                }
+            }
+        } catch (RemoteException e) {
+            Slog.w(getTag(), "am.getRunningAppProcesses() failed");
+        }
+        return false;
+    }
+
+    /**
+     * Calls the HAL to switch states to the new task. If there's already a current task,
+     * it calls cancel() and sets mPendingClient to begin when the current task finishes
+     * ({@link BiometricConstants#BIOMETRIC_ERROR_CANCELED}).
+     *
+     * @param newClient the new client that wants to connect
+     * @param initiatedByClient true for authenticate, remove and enroll
+     */
+    private void startClient(ClientMonitor newClient, boolean initiatedByClient) {
+        ClientMonitor currentClient = mCurrentClient;
+        if (currentClient != null) {
+            if (DEBUG) Slog.v(getTag(), "request stop current client " +
+                    currentClient.getOwnerString());
+
+            // This check only matters for FingerprintService, since enumerate may call back
+            // multiple times.
+            if (currentClient instanceof FingerprintService.EnumerateClientImpl ||
+                    currentClient instanceof FingerprintService.RemovalClientImpl) {
+                // This condition means we're currently running internal diagnostics to
+                // remove extra fingerprints in the hardware and/or the software
+                // TODO: design an escape hatch in case client never finishes
+                if (newClient != null) {
+                    Slog.w(getTag(), "Internal cleanup in progress but trying to start client "
+                            + newClient.getClass().getSuperclass().getSimpleName()
+                            + "(" + newClient.getOwnerString() + ")"
+                            + ", initiatedByClient = " + initiatedByClient);
+                }
+            } else {
+                currentClient.stop(initiatedByClient);
+            }
+            mPendingClient = newClient;
+            mHandler.removeCallbacks(mResetClientState);
+            mHandler.postDelayed(mResetClientState, CANCEL_TIMEOUT_LIMIT);
+        } else if (newClient != null) {
+            mCurrentClient = newClient;
+            if (DEBUG) Slog.v(getTag(), "starting client "
+                    + newClient.getClass().getSuperclass().getSimpleName()
+                    + "(" + newClient.getOwnerString() + ")"
+                    + ", initiatedByClient = " + initiatedByClient);
+            notifyClientActiveCallbacks(true);
+
+            newClient.start();
+        }
+    }
+
+    protected void removeClient(ClientMonitor client) {
+        if (client != null) {
+            client.destroy();
+            if (client != mCurrentClient && mCurrentClient != null) {
+                Slog.w(getTag(), "Unexpected client: " + client.getOwnerString() + "expected: "
+                        + mCurrentClient.getOwnerString());
+            }
+        }
+        if (mCurrentClient != null) {
+            if (DEBUG) Slog.v(getTag(), "Done with client: " + client.getOwnerString());
+            mCurrentClient = null;
+        }
+        if (mPendingClient == null) {
+            notifyClientActiveCallbacks(false);
+        }
+    }
+
+    /**
+     * Populates existing authenticator ids. To be used only during the start of the service.
+     */
+    protected void loadAuthenticatorIds() {
+        // This operation can be expensive, so keep track of the elapsed time. Might need to move to
+        // background if it takes too long.
+        long t = System.currentTimeMillis();
+        mAuthenticatorIds.clear();
+        for (UserInfo user : UserManager.get(getContext()).getUsers(true /* excludeDying */)) {
+            int userId = getUserOrWorkProfileId(null, user.id);
+            if (!mAuthenticatorIds.containsKey(userId)) {
+                updateActiveGroup(userId, null);
+            }
+        }
+
+        t = System.currentTimeMillis() - t;
+        if (t > 1000) {
+            Slog.w(getTag(), "loadAuthenticatorIds() taking too long: " + t + "ms");
+        }
+    }
+
+    /**
+     * @param clientPackage the package of the caller
+     * @return the profile id
+     */
+    protected int getUserOrWorkProfileId(String clientPackage, int userId) {
+        if (!isKeyguard(clientPackage) && isWorkProfile(userId)) {
+            return userId;
+        }
+        return getEffectiveUserId(userId);
+    }
+
+    protected boolean isRestricted() {
+        // Only give privileged apps (like Settings) access to biometric info
+        final boolean restricted = !hasPermission(getManageBiometricPermission());
+        return restricted;
+    }
+
+    protected boolean hasPermission(String permission) {
+        return getContext().checkCallingOrSelfPermission(permission)
+                == PackageManager.PERMISSION_GRANTED;
+    }
+
+    protected void checkPermission(String permission) {
+        getContext().enforceCallingOrSelfPermission(permission,
+                "Must have " + permission + " permission.");
+    }
+
+    protected boolean isCurrentUserOrProfile(int userId) {
+        UserManager um = UserManager.get(mContext);
+        if (um == null) {
+            Slog.e(getTag(), "Unable to acquire UserManager");
+            return false;
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            // Allow current user or profiles of the current user...
+            for (int profileId : um.getEnabledProfileIds(ActivityManager.getCurrentUser())) {
+                if (profileId == userId) {
+                    return true;
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+
+        return false;
+    }
+
+    /***
+     * @param opPackageName the name of the calling package
+     * @return authenticator id for the calling user
+     */
+    protected long getAuthenticatorId(String opPackageName) {
+        final int userId = getUserOrWorkProfileId(opPackageName, UserHandle.getCallingUserId());
+        return mAuthenticatorIds.getOrDefault(userId, 0L);
+    }
+
+    private void scheduleLockoutResetForUser(int userId) {
+        mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                SystemClock.elapsedRealtime() + FAIL_LOCKOUT_TIMEOUT_MS,
+                getLockoutResetIntentForUser(userId));
+    }
+
+    private PendingIntent getLockoutResetIntentForUser(int userId) {
+        return PendingIntent.getBroadcast(mContext, userId,
+                new Intent(getLockoutResetIntent()).putExtra(KEY_LOCKOUT_RESET_USER, userId),
+                PendingIntent.FLAG_UPDATE_CURRENT);
+    }
+
+    private void userActivity() {
+        long now = SystemClock.uptimeMillis();
+        mPowerManager.userActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
+    }
+
+    /**
+     * @param userId
+     * @return true if this is a work profile
+     */
+    private boolean isWorkProfile(int userId) {
+        UserInfo userInfo = null;
+        final long token = Binder.clearCallingIdentity();
+        try {
+            userInfo = mUserManager.getUserInfo(userId);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+        return userInfo != null && userInfo.isManagedProfile();
+    }
+
+
+    private int getEffectiveUserId(int userId) {
+        UserManager um = UserManager.get(mContext);
+        if (um != null) {
+            final long callingIdentity = Binder.clearCallingIdentity();
+            userId = um.getCredentialOwnerProfile(userId);
+            Binder.restoreCallingIdentity(callingIdentity);
+        } else {
+            Slog.e(getTag(), "Unable to acquire UserManager");
+        }
+        return userId;
+    }
+
+    // Attempt counter should only be cleared when Keyguard goes away or when
+    // a biometric is successfully authenticated.
+    private void resetFailedAttemptsForUser(boolean clearAttemptCounter, int userId) {
+        if (DEBUG && getLockoutMode() != AuthenticationClient.LOCKOUT_NONE) {
+            Slog.v(getTag(), "Reset biometric lockout, clearAttemptCounter=" + clearAttemptCounter);
+        }
+        if (clearAttemptCounter) {
+            mFailedAttempts.put(userId, 0);
+        }
+        mTimedLockoutCleared.put(userId, true);
+        // If we're asked to reset failed attempts externally (i.e. from Keyguard),
+        // the alarm might still be pending; remove it.
+        cancelLockoutResetForUser(userId);
+        notifyLockoutResetMonitors();
+    }
+
+    private void cancelLockoutResetForUser(int userId) {
+        mAlarmManager.cancel(getLockoutResetIntentForUser(userId));
+    }
+
+    private void listenForUserSwitches() {
+        try {
+            ActivityManager.getService().registerUserSwitchObserver(
+                    new SynchronousUserSwitchObserver() {
+                        @Override
+                        public void onUserSwitching(int newUserId) throws RemoteException {
+                            mHandler.obtainMessage(MSG_USER_SWITCHING, newUserId, 0 /* unused */)
+                                    .sendToTarget();
+                        }
+                    }, getTag());
+        } catch (RemoteException e) {
+            Slog.w(getTag(), "Failed to listen for user switching event" ,e);
+        }
+    }
+
+    private void notifyLockoutResetMonitors() {
+        for (int i = 0; i < mLockoutMonitors.size(); i++) {
+            mLockoutMonitors.get(i).sendLockoutReset();
+        }
+    }
+
+    private void removeLockoutResetCallback(
+            LockoutResetMonitor monitor) {
+        mLockoutMonitors.remove(monitor);
+    }
+}
diff --git a/services/core/java/com/android/server/biometrics/ClientMonitor.java b/services/core/java/com/android/server/biometrics/ClientMonitor.java
index d30bed2..d1daad5 100644
--- a/services/core/java/com/android/server/biometrics/ClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/ClientMonitor.java
@@ -28,6 +28,7 @@
 
 import com.android.internal.logging.MetricsLogger;
 
+import java.util.ArrayList;
 import java.util.NoSuchElementException;
 
 /**
@@ -37,7 +38,7 @@
  */
 public abstract class ClientMonitor implements IBinder.DeathRecipient {
     protected static final int ERROR_ESRCH = 3; // Likely HAL is dead. See errno.h.
-    protected static final boolean DEBUG = BiometricService.DEBUG;
+    protected static final boolean DEBUG = BiometricServiceBase.DEBUG;
     private static final AudioAttributes FINGERPRINT_SONFICATION_ATTRIBUTES =
             new AudioAttributes.Builder()
                     .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
@@ -53,10 +54,10 @@
     private final String mOwner;
     private final VibrationEffect mSuccessVibrationEffect;
     private final VibrationEffect mErrorVibrationEffect;
-    private final BiometricService.DaemonWrapper mDaemon;
+    private final BiometricServiceBase.DaemonWrapper mDaemon;
 
     private IBinder mToken;
-    private BiometricService.ServiceListener mListener;
+    private BiometricServiceBase.ServiceListener mListener;
 
     protected final MetricsLogger mMetricsLogger;
     protected final Metrics mMetrics;
@@ -75,9 +76,10 @@
      * permission
      * @param owner name of the client that owns this
      */
-    public ClientMonitor(Context context, Metrics metrics, BiometricService.DaemonWrapper daemon,
-            long halDeviceId, IBinder token, BiometricService.ServiceListener listener, int userId,
-            int groupId, boolean restricted, String owner) {
+    public ClientMonitor(Context context, Metrics metrics,
+            BiometricServiceBase.DaemonWrapper daemon, long halDeviceId, IBinder token,
+            BiometricServiceBase.ServiceListener listener, int userId, int groupId,
+            boolean restricted, String owner) {
         mContext = context;
         mMetrics = metrics;
         mDaemon = daemon;
@@ -128,7 +130,7 @@
     public abstract boolean onEnrollResult(BiometricAuthenticator.Identifier identifier,
             int remaining);
     public abstract boolean onAuthenticated(BiometricAuthenticator.Identifier identifier,
-            boolean authenticated);
+            boolean authenticated, ArrayList<Byte> token);
     public abstract boolean onRemoved(BiometricAuthenticator.Identifier identifier,
             int remaining);
     public abstract boolean onEnumerationResult(
@@ -220,11 +222,11 @@
         return mOwner;
     }
 
-    public final BiometricService.ServiceListener getListener() {
+    public final BiometricServiceBase.ServiceListener getListener() {
         return mListener;
     }
 
-    public final BiometricService.DaemonWrapper getDaemonWrapper() {
+    public final BiometricServiceBase.DaemonWrapper getDaemonWrapper() {
         return mDaemon;
     }
 
diff --git a/services/core/java/com/android/server/biometrics/EnrollClient.java b/services/core/java/com/android/server/biometrics/EnrollClient.java
index c305eca6..76dc5a9 100644
--- a/services/core/java/com/android/server/biometrics/EnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/EnrollClient.java
@@ -23,6 +23,7 @@
 import android.os.RemoteException;
 import android.util.Slog;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 
 /**
@@ -34,10 +35,10 @@
     private final byte[] mCryptoToken;
     private final BiometricUtils mBiometricUtils;
 
-    public EnrollClient(Context context, Metrics metrics, BiometricService.DaemonWrapper daemon,
-            long halDeviceId, IBinder token, BiometricService.ServiceListener listener, int userId,
-            int groupId, byte[] cryptoToken, boolean restricted, String owner,
-            BiometricUtils utils) {
+    public EnrollClient(Context context, Metrics metrics,
+            BiometricServiceBase.DaemonWrapper daemon, long halDeviceId, IBinder token,
+            BiometricServiceBase.ServiceListener listener, int userId, int groupId,
+            byte[] cryptoToken, boolean restricted, String owner, BiometricUtils utils) {
         super(context, metrics, daemon, halDeviceId, token, listener, userId, groupId, restricted,
                 owner);
         mBiometricUtils = utils;
@@ -126,7 +127,7 @@
 
     @Override
     public boolean onAuthenticated(BiometricAuthenticator.Identifier identifier,
-            boolean authenticated) {
+            boolean authenticated, ArrayList<Byte> token) {
         if (DEBUG) Slog.w(getLogTag(), "onAuthenticated() called for enroll!");
         return true; // Invalid for EnrollClient
     }
diff --git a/services/core/java/com/android/server/biometrics/EnumerateClient.java b/services/core/java/com/android/server/biometrics/EnumerateClient.java
index b763769..47dc7ff 100644
--- a/services/core/java/com/android/server/biometrics/EnumerateClient.java
+++ b/services/core/java/com/android/server/biometrics/EnumerateClient.java
@@ -23,13 +23,16 @@
 import android.os.RemoteException;
 import android.util.Slog;
 
+import java.util.ArrayList;
+
 /**
  * A class to keep track of the enumeration state for a given client.
  */
 public abstract class EnumerateClient extends ClientMonitor {
-    public EnumerateClient(Context context, Metrics metrics, BiometricService.DaemonWrapper daemon,
-            long halDeviceId, IBinder token, BiometricService.ServiceListener listener, int groupId,
-            int userId, boolean restricted, String owner) {
+    public EnumerateClient(Context context, Metrics metrics,
+            BiometricServiceBase.DaemonWrapper daemon, long halDeviceId, IBinder token,
+            BiometricServiceBase.ServiceListener listener, int groupId, int userId,
+            boolean restricted, String owner) {
         super(context, metrics, daemon, halDeviceId, token, listener, userId, groupId, restricted,
                 owner);
     }
@@ -94,7 +97,7 @@
 
     @Override
     public boolean onAuthenticated(BiometricAuthenticator.Identifier identifier,
-            boolean authenticated) {
+            boolean authenticated, ArrayList<Byte> token) {
         if (DEBUG) Slog.w(getLogTag(), "onAuthenticated() called for enumerate!");
         return true; // Invalid for Enumerate.
     }
diff --git a/services/core/java/com/android/server/biometrics/RemovalClient.java b/services/core/java/com/android/server/biometrics/RemovalClient.java
index 3bf7f04..15b3773 100644
--- a/services/core/java/com/android/server/biometrics/RemovalClient.java
+++ b/services/core/java/com/android/server/biometrics/RemovalClient.java
@@ -23,6 +23,8 @@
 import android.os.RemoteException;
 import android.util.Slog;
 
+import java.util.ArrayList;
+
 /**
  * A class to keep track of the remove state for a given client.
  */
@@ -30,10 +32,10 @@
     private final int mBiometricId;
     private final BiometricUtils mBiometricUtils;
 
-    public RemovalClient(Context context, Metrics metrics, BiometricService.DaemonWrapper daemon,
-            long halDeviceId, IBinder token, BiometricService.ServiceListener listener,
-            int biometricId, int groupId, int userId, boolean restricted, String owner,
-            BiometricUtils utils) {
+    public RemovalClient(Context context, Metrics metrics,
+            BiometricServiceBase.DaemonWrapper daemon, long halDeviceId, IBinder token,
+            BiometricServiceBase.ServiceListener listener, int biometricId, int groupId, int userId,
+            boolean restricted, String owner, BiometricUtils utils) {
         super(context, metrics, daemon, halDeviceId, token, listener, userId, groupId, restricted,
                 owner);
         mBiometricId = biometricId;
@@ -111,7 +113,7 @@
 
     @Override
     public boolean onAuthenticated(BiometricAuthenticator.Identifier identifier,
-            boolean authenticated) {
+            boolean authenticated, ArrayList<Byte> token) {
         if (DEBUG) Slog.w(getLogTag(), "onAuthenticated() called for remove!");
         return true; // Invalid for Remove.
     }
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index 8afac97..f6af52a 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -28,10 +28,11 @@
 import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.BiometricConstants;
 import android.hardware.biometrics.IBiometricPromptReceiver;
-import android.hardware.biometrics.IBiometricPromptServiceReceiver;
 import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
+import android.hardware.biometrics.IBiometricServiceReceiver;
 import android.hardware.biometrics.face.V1_0.IBiometricsFace;
 import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback;
+import android.hardware.biometrics.face.V1_0.Status;
 import android.hardware.face.Face;
 import android.hardware.face.FaceManager;
 import android.hardware.face.IFaceService;
@@ -49,9 +50,10 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.DumpUtils;
 import com.android.server.SystemServerInitThreadPool;
-import com.android.server.biometrics.BiometricService;
+import com.android.server.biometrics.BiometricServiceBase;
 import com.android.server.biometrics.BiometricUtils;
 import com.android.server.biometrics.Metrics;
 
@@ -72,7 +74,7 @@
  *
  * @hide
  */
-public class FaceService extends BiometricService {
+public class FaceService extends BiometricServiceBase {
 
     protected static final String TAG = "FaceService";
     private static final boolean DEBUG = true;
@@ -81,6 +83,35 @@
             "com.android.server.biometrics.face.ACTION_LOCKOUT_RESET";
     private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED = 3;
     private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT = 12;
+    private static final int CHALLENGE_TIMEOUT_SEC = 600; // 10 minutes
+
+    private final class FaceAuthClient extends AuthenticationClientImpl {
+        public FaceAuthClient(Context context,
+                DaemonWrapper daemon, long halDeviceId, IBinder token,
+                ServiceListener listener, int targetUserId, int groupId, long opId,
+                boolean restricted, String owner, Bundle bundle,
+                IBiometricPromptReceiver dialogReceiver, IStatusBarService statusBarService,
+                boolean requireConfirmation) {
+            super(context, daemon, halDeviceId, token, listener, targetUserId, groupId, opId,
+                    restricted, owner, bundle, dialogReceiver, statusBarService,
+                    requireConfirmation);
+        }
+
+        @Override
+        public String getErrorString(int error, int vendorCode) {
+            return FaceManager.getErrorString(getContext(), error, vendorCode);
+        }
+
+        @Override
+        public String getAcquiredString(int acquireInfo, int vendorCode) {
+            return FaceManager.getAcquiredString(getContext(), acquireInfo, vendorCode);
+        }
+
+        @Override
+        public int getBiometricType() {
+            return BiometricAuthenticator.TYPE_FACE;
+        }
+    }
 
     /**
      * Receives the incoming binder calls from FaceManager.
@@ -91,15 +122,15 @@
          * The following methods contain common code which is shared in biometrics/common.
          */
         @Override // Binder call
-        public long preEnroll(IBinder token) {
+        public long generateChallenge(IBinder token) {
             checkPermission(MANAGE_BIOMETRIC);
-            return startPreEnroll(token);
+            return startGenerateChallenge(token);
         }
 
         @Override // Binder call
-        public int postEnroll(IBinder token) {
+        public int revokeChallenge(IBinder token) {
             checkPermission(MANAGE_BIOMETRIC);
-            return startPostEnroll(token);
+            return startRevokeChallenge(token);
         }
 
         @Override // Binder call
@@ -128,26 +159,26 @@
                 final String opPackageName) {
             checkPermission(USE_BIOMETRIC_INTERNAL);
             final boolean restricted = isRestricted();
-            final AuthenticationClientImpl client = new AuthenticationClientImpl(getContext(),
+            final AuthenticationClientImpl client = new FaceAuthClient(getContext(),
                     mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver),
                     mCurrentUserId, 0 /* groupId */, opId, restricted, opPackageName,
-                    null /* bundle */, null /* dialogReceiver */, mStatusBarService, mFaceManager);
-
+                    null /* bundle */, null /* dialogReceiver */, mStatusBarService,
+                    false /* requireConfirmation */);
             authenticateInternal(client, opId, opPackageName);
         }
 
         @Override // Binder call
-        public void authenticateFromService(IBinder token, long opId, int groupId,
-                IBiometricPromptServiceReceiver receiver, int flags, String opPackageName,
-                Bundle bundle, IBiometricPromptReceiver dialogReceiver,
+        public void authenticateFromService(boolean requireConfirmation, IBinder token, long opId,
+                int groupId, IBiometricServiceReceiver receiver, int flags,
+                String opPackageName, Bundle bundle, IBiometricPromptReceiver dialogReceiver,
                 int callingUid, int callingPid, int callingUserId) {
             checkPermission(USE_BIOMETRIC_INTERNAL);
             final boolean restricted = true; // BiometricPrompt is always restricted
-            final AuthenticationClientImpl client = new AuthenticationClientImpl(getContext(),
+            final AuthenticationClientImpl client = new FaceAuthClient(getContext(),
                     mDaemonWrapper, mHalDeviceId, token,
                     new BiometricPromptServiceListenerImpl(receiver),
                     mCurrentUserId, 0 /* groupId */, opId, restricted, opPackageName,
-                    bundle, dialogReceiver, mStatusBarService, mFaceManager);
+                    bundle, dialogReceiver, mStatusBarService, true /* requireConfirmation */);
             authenticateInternal(client, opId, opPackageName, callingUid, callingPid,
                     callingUserId);
         }
@@ -316,6 +347,45 @@
             // TODO: confirm security token when we move timeout management into the HAL layer.
             mHandler.post(mResetFailedAttemptsForCurrentUserRunnable);
         }
+
+        @Override
+        public int setRequireAttention(boolean requireAttention, final byte[] token) {
+            checkPermission(MANAGE_BIOMETRIC);
+
+            final ArrayList<Byte> byteToken = new ArrayList<>();
+            for (int i = 0; i < token.length; i++) {
+                byteToken.add(token[i]);
+            }
+
+            int result;
+            try {
+                result = mDaemon != null ? mDaemon.setRequireAttention(requireAttention, byteToken)
+                        : Status.INTERNAL_ERROR;
+            } catch (RemoteException e) {
+                Slog.e(getTag(), "Unable to setRequireAttention to " + requireAttention);
+                result = Status.INTERNAL_ERROR;
+            }
+
+            return result;
+        }
+
+        @Override
+        public boolean getRequireAttention(final byte[] token) {
+            checkPermission(MANAGE_BIOMETRIC);
+
+            final ArrayList<Byte> byteToken = new ArrayList<>();
+            for (int i = 0; i < token.length; i++) {
+                byteToken.add(token[i]);
+            }
+
+            boolean result = true;
+            try {
+                result = mDaemon != null ? mDaemon.getRequireAttention(byteToken).value : true;
+            } catch (RemoteException e) {
+                Slog.e(getTag(), "Unable to getRequireAttention");
+            }
+            return result;
+        }
     }
 
     /**
@@ -324,10 +394,10 @@
      */
     private class BiometricPromptServiceListenerImpl implements ServiceListener {
 
-        private IBiometricPromptServiceReceiver mBiometricPromptServiceReceiver;
+        private IBiometricServiceReceiver mBiometricServiceReceiver;
 
-        public BiometricPromptServiceListenerImpl(IBiometricPromptServiceReceiver receiver) {
-            mBiometricPromptServiceReceiver = receiver;
+        public BiometricPromptServiceListenerImpl(IBiometricServiceReceiver receiver) {
+            mBiometricServiceReceiver = receiver;
         }
 
         @Override
@@ -336,33 +406,33 @@
             /**
              * Map the acquired codes onto existing {@link BiometricConstants} acquired codes.
              */
-            if (mBiometricPromptServiceReceiver != null) {
-                mBiometricPromptServiceReceiver.onAcquired(deviceId,
-                        mFaceManager.getMappedAcquiredInfo(acquiredInfo, vendorCode),
-                        mFaceManager.getAcquiredString(acquiredInfo, vendorCode));
+            if (mBiometricServiceReceiver != null) {
+                mBiometricServiceReceiver.onAcquired(deviceId,
+                        FaceManager.getMappedAcquiredInfo(acquiredInfo, vendorCode),
+                        FaceManager.getAcquiredString(getContext(), acquiredInfo, vendorCode));
             }
         }
 
         @Override
         public void onAuthenticationSucceeded(long deviceId,
                 BiometricAuthenticator.Identifier biometric, int userId) throws RemoteException {
-            if (mBiometricPromptServiceReceiver != null) {
-                mBiometricPromptServiceReceiver.onAuthenticationSucceeded(deviceId);
+            if (mBiometricServiceReceiver != null) {
+                mBiometricServiceReceiver.onAuthenticationSucceeded(deviceId);
             }
         }
 
         @Override
         public void onAuthenticationFailed(long deviceId) throws RemoteException {
-            if (mBiometricPromptServiceReceiver != null) {
-                mBiometricPromptServiceReceiver.onAuthenticationFailed(deviceId);
+            if (mBiometricServiceReceiver != null) {
+                mBiometricServiceReceiver.onAuthenticationFailed(deviceId);
             }
         }
 
         @Override
         public void onError(long deviceId, int error, int vendorCode) throws RemoteException {
-            if (mBiometricPromptServiceReceiver != null) {
-                mBiometricPromptServiceReceiver.onError(deviceId, error,
-                        mFaceManager.getErrorString(error, vendorCode));
+            if (mBiometricServiceReceiver != null) {
+                mBiometricServiceReceiver.onError(deviceId, error,
+                        FaceManager.getErrorString(getContext(), error, vendorCode));
             }
         }
     }
@@ -447,8 +517,6 @@
     @GuardedBy("this")
     private IBiometricsFace mDaemon;
     private long mHalDeviceId;
-    // Use FaceManager to get strings, so BiometricPrompt interface is cleaner
-    private FaceManager mFaceManager;
 
     /**
      * Receives callbacks from the HAL.
@@ -589,7 +657,6 @@
         super.onStart();
         publishBinderService(Context.FACE_SERVICE, new FaceServiceWrapper());
         SystemServerInitThreadPool.get().submit(this::getFaceDaemon, TAG + ".onStart");
-        mFaceManager = (FaceManager) getContext().getSystemService(Context.FACE_SERVICE);
     }
 
     @Override
@@ -704,8 +771,9 @@
     }
 
     @Override
-    protected int getAppOp() {
-        return AppOpsManager.OP_USE_FACE;
+    protected boolean checkAppOps(int uid, String opPackageName) {
+        return mAppOps.noteOp(AppOpsManager.OP_USE_BIOMETRIC, uid, opPackageName)
+                == AppOpsManager.MODE_ALLOWED;
     }
 
     @Override
@@ -751,30 +819,30 @@
         return mDaemon;
     }
 
-    private long startPreEnroll(IBinder token) {
+    private long startGenerateChallenge(IBinder token) {
         IBiometricsFace daemon = getFaceDaemon();
         if (daemon == null) {
-            Slog.w(TAG, "startPreEnroll: no face HAL!");
+            Slog.w(TAG, "startGenerateChallenge: no face HAL!");
             return 0;
         }
         try {
-            return daemon.generateChallenge().value;
+            return daemon.generateChallenge(CHALLENGE_TIMEOUT_SEC).value;
         } catch (RemoteException e) {
-            Slog.e(TAG, "startPreEnroll failed", e);
+            Slog.e(TAG, "startGenerateChallenge failed", e);
         }
         return 0;
     }
 
-    private int startPostEnroll(IBinder token) {
+    private int startRevokeChallenge(IBinder token) {
         IBiometricsFace daemon = getFaceDaemon();
         if (daemon == null) {
-            Slog.w(TAG, "startPostEnroll: no face HAL!");
+            Slog.w(TAG, "startRevokeChallenge: no face HAL!");
             return 0;
         }
         try {
             return daemon.revokeChallenge();
         } catch (RemoteException e) {
-            Slog.e(TAG, "startPostEnroll failed", e);
+            Slog.e(TAG, "startRevokeChallenge failed", e);
         }
         return 0;
     }
@@ -862,4 +930,4 @@
         mPerformanceMap.clear();
         mCryptoPerformanceMap.clear();
     }
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
index 95fb9e3..b0b788f 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -31,7 +31,7 @@
 import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.BiometricConstants;
 import android.hardware.biometrics.IBiometricPromptReceiver;
-import android.hardware.biometrics.IBiometricPromptServiceReceiver;
+import android.hardware.biometrics.IBiometricServiceReceiver;
 import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
 import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
 import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprintClientCallback;
@@ -50,13 +50,16 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Slog;
+import android.util.StatsLog;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.DumpUtils;
 import com.android.server.SystemServerInitThreadPool;
-import com.android.server.biometrics.BiometricService;
+import com.android.server.biometrics.AuthenticationClient;
+import com.android.server.biometrics.BiometricServiceBase;
 import com.android.server.biometrics.BiometricUtils;
 import com.android.server.biometrics.ClientMonitor;
 import com.android.server.biometrics.EnumerateClient;
@@ -81,7 +84,7 @@
  *
  * @hide
  */
-public class FingerprintService extends BiometricService {
+public class FingerprintService extends BiometricServiceBase {
 
     protected static final String TAG = "FingerprintService";
     private static final boolean DEBUG = true;
@@ -102,6 +105,34 @@
         }
     }
 
+    private final class FingerprintAuthClient extends AuthenticationClientImpl {
+        public FingerprintAuthClient(Context context,
+                DaemonWrapper daemon, long halDeviceId, IBinder token,
+                ServiceListener listener, int targetUserId, int groupId, long opId,
+                boolean restricted, String owner, Bundle bundle,
+                IBiometricPromptReceiver dialogReceiver, IStatusBarService statusBarService,
+                boolean requireConfirmation) {
+            super(context, daemon, halDeviceId, token, listener, targetUserId, groupId, opId,
+                    restricted, owner, bundle, dialogReceiver, statusBarService,
+                    requireConfirmation);
+        }
+
+        @Override
+        public String getErrorString(int error, int vendorCode) {
+            return FingerprintManager.getErrorString(getContext(), error, vendorCode);
+        }
+
+        @Override
+        public String getAcquiredString(int acquireInfo, int vendorCode) {
+            return FingerprintManager.getAcquiredString(getContext(), acquireInfo, vendorCode);
+        }
+
+        @Override
+        public int getBiometricType() {
+            return BiometricAuthenticator.TYPE_FINGERPRINT;
+        }
+    }
+
     /**
      * Receives the incoming binder calls from FingerprintManager.
      */
@@ -149,26 +180,25 @@
                 final IFingerprintServiceReceiver receiver, final int flags,
                 final String opPackageName) {
             final boolean restricted = isRestricted();
-            final AuthenticationClientImpl client = new AuthenticationClientImpl(getContext(),
+            final AuthenticationClientImpl client = new FingerprintAuthClient(getContext(),
                     mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver),
                     mCurrentUserId, groupId, opId, restricted, opPackageName, null /* bundle */,
-                    null /* dialogReceiver */, mStatusBarService, mFingerprintManager);
-
+                    null /* dialogReceiver */, mStatusBarService, false /* requireConfirmation */);
             authenticateInternal(client, opId, opPackageName);
         }
 
         @Override // Binder call
         public void authenticateFromService(IBinder token, long opId, int groupId,
-                IBiometricPromptServiceReceiver receiver, int flags, String opPackageName,
+                IBiometricServiceReceiver receiver, int flags, String opPackageName,
                 Bundle bundle, IBiometricPromptReceiver dialogReceiver,
                 int callingUid, int callingPid, int callingUserId) {
             checkPermission(MANAGE_BIOMETRIC);
             final boolean restricted = true; // BiometricPrompt is always restricted
-            final AuthenticationClientImpl client = new AuthenticationClientImpl(getContext(),
+            final AuthenticationClientImpl client = new FingerprintAuthClient(getContext(),
                     mDaemonWrapper, mHalDeviceId, token,
                     new BiometricPromptServiceListenerImpl(receiver),
                     mCurrentUserId, groupId, opId, restricted, opPackageName, bundle,
-                    dialogReceiver, mStatusBarService, mFingerprintManager);
+                    dialogReceiver, mStatusBarService, false /* requireConfirmation */);
             authenticateInternal(client, opId, opPackageName, callingUid, callingPid,
                     callingUserId);
         }
@@ -360,41 +390,42 @@
      */
     private class BiometricPromptServiceListenerImpl implements ServiceListener {
 
-        private IBiometricPromptServiceReceiver mBiometricPromptServiceReceiver;
+        private IBiometricServiceReceiver mBiometricServiceReceiver;
 
-        public BiometricPromptServiceListenerImpl(IBiometricPromptServiceReceiver receiver) {
-            mBiometricPromptServiceReceiver = receiver;
+        public BiometricPromptServiceListenerImpl(IBiometricServiceReceiver receiver) {
+            mBiometricServiceReceiver = receiver;
         }
 
         @Override
         public void onAcquired(long deviceId, int acquiredInfo, int vendorCode)
                 throws RemoteException {
-            if (mBiometricPromptServiceReceiver != null) {
-                mBiometricPromptServiceReceiver.onAcquired(deviceId, acquiredInfo,
-                        mFingerprintManager.getAcquiredString(acquiredInfo, vendorCode));
+            if (mBiometricServiceReceiver != null) {
+                mBiometricServiceReceiver.onAcquired(deviceId, acquiredInfo,
+                        FingerprintManager.getAcquiredString(
+                            getContext(), acquiredInfo, vendorCode));
             }
         }
 
         @Override
         public void onAuthenticationSucceeded(long deviceId,
                 BiometricAuthenticator.Identifier biometric, int userId) throws RemoteException {
-            if (mBiometricPromptServiceReceiver != null) {
-                mBiometricPromptServiceReceiver.onAuthenticationSucceeded(deviceId);
+            if (mBiometricServiceReceiver != null) {
+                mBiometricServiceReceiver.onAuthenticationSucceeded(deviceId);
             }
         }
 
         @Override
         public void onAuthenticationFailed(long deviceId) throws RemoteException {
-            if (mBiometricPromptServiceReceiver != null) {
-                mBiometricPromptServiceReceiver.onAuthenticationFailed(deviceId);
+            if (mBiometricServiceReceiver != null) {
+                mBiometricServiceReceiver.onAuthenticationFailed(deviceId);
             }
         }
 
         @Override
         public void onError(long deviceId, int error, int vendorCode) throws RemoteException {
-            if (mBiometricPromptServiceReceiver != null) {
-                mBiometricPromptServiceReceiver.onError(deviceId, error,
-                        mFingerprintManager.getErrorString(error, vendorCode));
+            if (mBiometricServiceReceiver != null) {
+                mBiometricServiceReceiver.onError(deviceId, error,
+                        FingerprintManager.getErrorString(getContext(), error, vendorCode));
             }
         }
     }
@@ -483,7 +514,7 @@
     /**
      * An internal class to help clean up unknown fingerprints in the hardware and software.
      */
-    private final class InternalEnumerateClient extends BiometricService.EnumerateClientImpl {
+    private final class InternalEnumerateClient extends BiometricServiceBase.EnumerateClientImpl {
 
         private List<Fingerprint> mEnrolledList;
         private List<Fingerprint> mUnknownFingerprints = new ArrayList<>(); // list of fp to delete
@@ -546,7 +577,7 @@
     /**
      * An internal class to help clean up unknown fingerprints in hardware and software.
      */
-    private final class InternalRemovalClient extends BiometricService.RemovalClientImpl {
+    private final class InternalRemovalClient extends BiometricServiceBase.RemovalClientImpl {
         public InternalRemovalClient(Context context,
                 DaemonWrapper daemon, long halDeviceId, IBinder token,
                 ServiceListener listener, int fingerId, int groupId, int userId, boolean restricted,
@@ -567,8 +598,6 @@
     private long mHalDeviceId;
     private IBinder mToken = new Binder(); // used for internal FingerprintService enumeration
     private ArrayList<UserFingerprint> mUnknownFingerprints = new ArrayList<>(); // hw fingerprints
-    // Use FingerprintManager to get strings, so BiometricPrompt interface is cleaner.
-    private FingerprintManager mFingerprintManager;
 
     /**
      * Receives callbacks from the HAL.
@@ -590,6 +619,11 @@
         public void onAcquired(final long deviceId, final int acquiredInfo, final int vendorCode) {
             mHandler.post(() -> {
                 FingerprintService.super.handleAcquired(deviceId, acquiredInfo, vendorCode);
+                if (getLockoutMode() == AuthenticationClient.LOCKOUT_NONE
+                        && getCurrentClient() instanceof AuthenticationClient) {
+                    // Ignore enrollment acquisitions or acquisitions when we are locked out.
+                    StatsLog.write(StatsLog.FINGERPRINT_ACQUIRED, mCurrentUserId, mIsCrypto);
+                }
             });
         }
 
@@ -599,6 +633,22 @@
             mHandler.post(() -> {
                 Fingerprint fp = new Fingerprint("", groupId, fingerId, deviceId);
                 FingerprintService.super.handleAuthenticated(fp, token);
+                // Send authentication to statsd.
+                final boolean authenticated = fingerId != 0;
+                StatsLog.write(StatsLog.FINGERPRINT_AUTHENTICATED, mCurrentUserId, mIsCrypto,
+                        authenticated);
+                if (!authenticated) {
+                    // If we failed to authenticate because of a lockout, inform statsd.
+                    final int lockoutMode = getLockoutMode();
+                    if (lockoutMode == AuthenticationClient.LOCKOUT_TIMED) {
+                        StatsLog.write(StatsLog.FINGERPRINT_ERROR_OCCURRED, mCurrentUserId,
+                                mIsCrypto, StatsLog.FINGERPRINT_ERROR_OCCURRED__ERROR__LOCKOUT);
+                    } else if (lockoutMode == AuthenticationClient.LOCKOUT_PERMANENT) {
+                        StatsLog.write(StatsLog.FINGERPRINT_ERROR_OCCURRED, mCurrentUserId,
+                                mIsCrypto,
+                                StatsLog.FINGERPRINT_ERROR_OCCURRED__ERROR__PERMANENT_LOCKOUT);
+                    }
+                }
             });
         }
 
@@ -717,8 +767,6 @@
         super.onStart();
         publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
         SystemServerInitThreadPool.get().submit(this::getFingerprintDaemon, TAG + ".onStart");
-        mFingerprintManager = (FingerprintManager)
-                getContext().getSystemService(Context.FINGERPRINT_SERVICE);
     }
 
     @Override
@@ -854,8 +902,16 @@
     }
 
     @Override
-    protected int getAppOp() {
-        return AppOpsManager.OP_USE_FINGERPRINT;
+    protected boolean checkAppOps(int uid, String opPackageName) {
+        boolean appOpsOk = false;
+        if (mAppOps.noteOp(AppOpsManager.OP_USE_BIOMETRIC, uid, opPackageName)
+                == AppOpsManager.MODE_ALLOWED) {
+            appOpsOk = true;
+        } else if (mAppOps.noteOp(AppOpsManager.OP_USE_FINGERPRINT, uid, opPackageName)
+                == AppOpsManager.MODE_ALLOWED) {
+            appOpsOk = true;
+        }
+        return appOpsOk;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index c028a43..873a8e3 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -639,12 +639,20 @@
             }
         }
 
-        // Otherwise only focused applications can access the clipboard.
-        boolean uidFocused = mWm.isUidFocused(callingUid);
-        if (!uidFocused) {
-            Slog.e(TAG, "Denying clipboard access to " + callingPackage
-                    + ", application is not in focus.");
+        switch (op) {
+            case AppOpsManager.OP_READ_CLIPBOARD:
+                // Clipboard can only be read by applications with focus.
+                boolean uidFocused = mWm.isUidFocused(callingUid);
+                if (!uidFocused) {
+                    Slog.e(TAG, "Denying clipboard access to " + callingPackage
+                            + ", application is not in focus.");
+                }
+                return uidFocused;
+            case AppOpsManager.OP_WRITE_CLIPBOARD:
+                // Writing is allowed without focus.
+                return true;
+            default:
+                throw new IllegalArgumentException("Unknown clipboard appop " + op);
         }
-        return uidFocused;
     }
 }
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index d16c277..a8f7259 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -68,6 +68,7 @@
 import android.hardware.usb.UsbManager;
 import android.net.INetworkPolicyManager;
 import android.net.INetworkStatsService;
+import android.net.ip.IpServer;
 import android.net.IpPrefix;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
@@ -112,10 +113,8 @@
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
 import com.android.server.LocalServices;
-import com.android.server.connectivity.tethering.IControlsTethering;
 import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
 import com.android.server.connectivity.tethering.OffloadController;
-import com.android.server.connectivity.tethering.TetherInterfaceStateMachine;
 import com.android.server.connectivity.tethering.TetheringConfiguration;
 import com.android.server.connectivity.tethering.TetheringDependencies;
 import com.android.server.connectivity.tethering.TetheringInterfaceUtils;
@@ -149,7 +148,7 @@
     protected static final String DISABLE_PROVISIONING_SYSPROP_KEY = "net.tethering.noprovisioning";
 
     private static final Class[] messageClasses = {
-            Tethering.class, TetherMasterSM.class, TetherInterfaceStateMachine.class
+            Tethering.class, TetherMasterSM.class, IpServer.class
     };
     private static final SparseArray<String> sMagicDecoderRing =
             MessageUtils.findMessageNames(messageClasses);
@@ -159,21 +158,21 @@
             .getSystem().getString(com.android.internal.R.string.config_wifi_tether_enable));
 
     private static class TetherState {
-        public final TetherInterfaceStateMachine stateMachine;
+        public final IpServer ipServer;
         public int lastState;
         public int lastError;
 
-        public TetherState(TetherInterfaceStateMachine sm) {
-            stateMachine = sm;
+        public TetherState(IpServer ipServer) {
+            this.ipServer = ipServer;
             // Assume all state machines start out available and with no errors.
-            lastState = IControlsTethering.STATE_AVAILABLE;
+            lastState = IpServer.STATE_AVAILABLE;
             lastError = TETHER_ERROR_NO_ERROR;
         }
 
         public boolean isCurrentlyServing() {
             switch (lastState) {
-                case IControlsTethering.STATE_TETHERED:
-                case IControlsTethering.STATE_LOCAL_ONLY:
+                case IpServer.STATE_TETHERED:
+                case IpServer.STATE_LOCAL_ONLY:
                     return true;
                 default:
                     return false;
@@ -198,7 +197,7 @@
     private final UpstreamNetworkMonitor mUpstreamNetworkMonitor;
     // TODO: Figure out how to merge this and other downstream-tracking objects
     // into a single coherent structure.
-    private final HashSet<TetherInterfaceStateMachine> mForwardedDownstreams;
+    private final HashSet<IpServer> mForwardedDownstreams;
     private final VersionedBroadcastListener mCarrierConfigChange;
     private final TetheringDependencies mDeps;
 
@@ -604,7 +603,7 @@
     }
 
     public int tether(String iface) {
-        return tether(iface, IControlsTethering.STATE_TETHERED);
+        return tether(iface, IpServer.STATE_TETHERED);
     }
 
     private int tether(String iface, int requestedState) {
@@ -617,7 +616,7 @@
             }
             // Ignore the error status of the interface.  If the interface is available,
             // the errors are referring to past tethering attempts anyway.
-            if (tetherState.lastState != IControlsTethering.STATE_AVAILABLE) {
+            if (tetherState.lastState != IpServer.STATE_AVAILABLE) {
                 Log.e(TAG, "Tried to Tether an unavailable iface: " + iface + ", ignoring");
                 return TETHER_ERROR_UNAVAIL_IFACE;
             }
@@ -626,8 +625,7 @@
             // return an error.
             //
             // TODO: reexamine the threading and messaging model.
-            tetherState.stateMachine.sendMessage(
-                    TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, requestedState);
+            tetherState.ipServer.sendMessage(IpServer.CMD_TETHER_REQUESTED, requestedState);
             return TETHER_ERROR_NO_ERROR;
         }
     }
@@ -644,8 +642,7 @@
                 Log.e(TAG, "Tried to untether an inactive iface :" + iface + ", ignoring");
                 return TETHER_ERROR_UNAVAIL_IFACE;
             }
-            tetherState.stateMachine.sendMessage(
-                    TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
+            tetherState.ipServer.sendMessage(IpServer.CMD_TETHER_UNREQUESTED);
             return TETHER_ERROR_NO_ERROR;
         }
     }
@@ -689,11 +686,11 @@
                 String iface = mTetherStates.keyAt(i);
                 if (tetherState.lastError != TETHER_ERROR_NO_ERROR) {
                     erroredList.add(iface);
-                } else if (tetherState.lastState == IControlsTethering.STATE_AVAILABLE) {
+                } else if (tetherState.lastState == IpServer.STATE_AVAILABLE) {
                     availableList.add(iface);
-                } else if (tetherState.lastState == IControlsTethering.STATE_LOCAL_ONLY) {
+                } else if (tetherState.lastState == IpServer.STATE_LOCAL_ONLY) {
                     localOnlyList.add(iface);
-                } else if (tetherState.lastState == IControlsTethering.STATE_TETHERED) {
+                } else if (tetherState.lastState == IpServer.STATE_TETHERED) {
                     if (cfg.isUsb(iface)) {
                         usbTethered = true;
                     } else if (cfg.isWifi(iface)) {
@@ -882,10 +879,10 @@
             synchronized (Tethering.this.mPublicSync) {
                 if (!usbConnected && mRndisEnabled) {
                     // Turn off tethering if it was enabled and there is a disconnect.
-                    tetherMatchingInterfaces(IControlsTethering.STATE_AVAILABLE, TETHERING_USB);
+                    tetherMatchingInterfaces(IpServer.STATE_AVAILABLE, TETHERING_USB);
                 } else if (usbConfigured && rndisEnabled) {
                     // Tether if rndis is enabled and usb is configured.
-                    tetherMatchingInterfaces(IControlsTethering.STATE_TETHERED, TETHERING_USB);
+                    tetherMatchingInterfaces(IpServer.STATE_TETHERED, TETHERING_USB);
                 }
                 mRndisEnabled = usbConfigured && rndisEnabled;
             }
@@ -959,15 +956,15 @@
         if (!TextUtils.isEmpty(ifname)) {
             final TetherState ts = mTetherStates.get(ifname);
             if (ts != null) {
-                ts.stateMachine.unwanted();
+                ts.ipServer.unwanted();
                 return;
             }
         }
 
         for (int i = 0; i < mTetherStates.size(); i++) {
-            TetherInterfaceStateMachine tism = mTetherStates.valueAt(i).stateMachine;
-            if (tism.interfaceType() == TETHERING_WIFI) {
-                tism.unwanted();
+            final IpServer ipServer = mTetherStates.valueAt(i).ipServer;
+            if (ipServer.interfaceType() == TETHERING_WIFI) {
+                ipServer.unwanted();
                 return;
             }
         }
@@ -978,15 +975,15 @@
     }
 
     private void enableWifiIpServingLocked(String ifname, int wifiIpMode) {
-        // Map wifiIpMode values to IControlsTethering serving states, inferring
+        // Map wifiIpMode values to IpServer.Callback serving states, inferring
         // from mWifiTetherRequested as a final "best guess".
         final int ipServingMode;
         switch (wifiIpMode) {
             case IFACE_IP_MODE_TETHERED:
-                ipServingMode = IControlsTethering.STATE_TETHERED;
+                ipServingMode = IpServer.STATE_TETHERED;
                 break;
             case IFACE_IP_MODE_LOCAL_ONLY:
-                ipServingMode = IControlsTethering.STATE_LOCAL_ONLY;
+                ipServingMode = IpServer.STATE_LOCAL_ONLY;
                 break;
             default:
                 mLog.e("Cannot enable IP serving in unknown WiFi mode: " + wifiIpMode);
@@ -1041,12 +1038,12 @@
     private void changeInterfaceState(String ifname, int requestedState) {
         final int result;
         switch (requestedState) {
-            case IControlsTethering.STATE_UNAVAILABLE:
-            case IControlsTethering.STATE_AVAILABLE:
+            case IpServer.STATE_UNAVAILABLE:
+            case IpServer.STATE_AVAILABLE:
                 result = untether(ifname);
                 break;
-            case IControlsTethering.STATE_TETHERED:
-            case IControlsTethering.STATE_LOCAL_ONLY:
+            case IpServer.STATE_TETHERED:
+            case IpServer.STATE_LOCAL_ONLY:
                 result = tether(ifname, requestedState);
                 break;
             default:
@@ -1104,7 +1101,7 @@
         synchronized (mPublicSync) {
             for (int i = 0; i < mTetherStates.size(); i++) {
                 TetherState tetherState = mTetherStates.valueAt(i);
-                if (tetherState.lastState == IControlsTethering.STATE_TETHERED) {
+                if (tetherState.lastState == IpServer.STATE_TETHERED) {
                     list.add(mTetherStates.keyAt(i));
                 }
             }
@@ -1117,7 +1114,7 @@
         synchronized (mPublicSync) {
             for (int i = 0; i < mTetherStates.size(); i++) {
                 TetherState tetherState = mTetherStates.valueAt(i);
-                if (tetherState.lastState == IControlsTethering.STATE_AVAILABLE) {
+                if (tetherState.lastState == IpServer.STATE_AVAILABLE) {
                     list.add(mTetherStates.keyAt(i));
                 }
             }
@@ -1177,7 +1174,7 @@
         synchronized (mPublicSync) {
             for (int i = 0; i < mTetherStates.size(); i++) {
                 TetherState tetherState = mTetherStates.valueAt(i);
-                if (tetherState.lastState != IControlsTethering.STATE_TETHERED) {
+                if (tetherState.lastState != IpServer.STATE_TETHERED) {
                     continue;  // Skip interfaces that aren't tethered.
                 }
                 String iface = mTetherStates.keyAt(i);
@@ -1231,7 +1228,7 @@
         // Because we excise interfaces immediately from mTetherStates, we must maintain mNotifyList
         // so that the garbage collector does not clean up the state machine before it has a chance
         // to tear itself down.
-        private final ArrayList<TetherInterfaceStateMachine> mNotifyList;
+        private final ArrayList<IpServer> mNotifyList;
         private final IPv6TetheringCoordinator mIPv6TetheringCoordinator;
         private final OffloadWrapper mOffload;
 
@@ -1268,17 +1265,19 @@
             public boolean processMessage(Message message) {
                 logMessage(this, message.what);
                 switch (message.what) {
-                    case EVENT_IFACE_SERVING_STATE_ACTIVE:
-                        TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj;
+                    case EVENT_IFACE_SERVING_STATE_ACTIVE: {
+                        final IpServer who = (IpServer) message.obj;
                         if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
                         handleInterfaceServingStateActive(message.arg1, who);
                         transitionTo(mTetherModeAliveState);
                         break;
-                    case EVENT_IFACE_SERVING_STATE_INACTIVE:
-                        who = (TetherInterfaceStateMachine) message.obj;
+                    }
+                    case EVENT_IFACE_SERVING_STATE_INACTIVE: {
+                        final IpServer who = (IpServer) message.obj;
                         if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
                         handleInterfaceServingStateInactive(who);
                         break;
+                    }
                     case EVENT_IFACE_UPDATE_LINKPROPERTIES:
                         // Silently ignore these for now.
                         break;
@@ -1410,8 +1409,8 @@
 
         protected void notifyDownstreamsOfNewUpstreamIface(InterfaceSet ifaces) {
             mCurrentUpstreamIfaceSet = ifaces;
-            for (TetherInterfaceStateMachine sm : mNotifyList) {
-                sm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED, ifaces);
+            for (IpServer ipServer : mNotifyList) {
+                ipServer.sendMessage(IpServer.CMD_TETHER_CONNECTION_CHANGED, ifaces);
             }
         }
 
@@ -1420,13 +1419,13 @@
             mOffload.updateUpstreamNetworkState(ns);
         }
 
-        private void handleInterfaceServingStateActive(int mode, TetherInterfaceStateMachine who) {
+        private void handleInterfaceServingStateActive(int mode, IpServer who) {
             if (mNotifyList.indexOf(who) < 0) {
                 mNotifyList.add(who);
                 mIPv6TetheringCoordinator.addActiveDownstream(who, mode);
             }
 
-            if (mode == IControlsTethering.STATE_TETHERED) {
+            if (mode == IpServer.STATE_TETHERED) {
                 // No need to notify OffloadController just yet as there are no
                 // "offload-able" prefixes to pass along. This will handled
                 // when the TISM informs Tethering of its LinkProperties.
@@ -1441,10 +1440,10 @@
                 final WifiManager mgr = getWifiManager();
                 final String iface = who.interfaceName();
                 switch (mode) {
-                    case IControlsTethering.STATE_TETHERED:
+                    case IpServer.STATE_TETHERED:
                         mgr.updateInterfaceIpState(iface, IFACE_IP_MODE_TETHERED);
                         break;
-                    case IControlsTethering.STATE_LOCAL_ONLY:
+                    case IpServer.STATE_LOCAL_ONLY:
                         mgr.updateInterfaceIpState(iface, IFACE_IP_MODE_LOCAL_ONLY);
                         break;
                     default:
@@ -1454,7 +1453,7 @@
             }
         }
 
-        private void handleInterfaceServingStateInactive(TetherInterfaceStateMachine who) {
+        private void handleInterfaceServingStateInactive(IpServer who) {
             mNotifyList.remove(who);
             mIPv6TetheringCoordinator.removeActiveDownstream(who);
             mOffload.excludeDownstreamInterface(who.interfaceName());
@@ -1563,10 +1562,10 @@
                 boolean retValue = true;
                 switch (message.what) {
                     case EVENT_IFACE_SERVING_STATE_ACTIVE: {
-                        TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj;
+                        IpServer who = (IpServer) message.obj;
                         if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
                         handleInterfaceServingStateActive(message.arg1, who);
-                        who.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
+                        who.sendMessage(IpServer.CMD_TETHER_CONNECTION_CHANGED,
                                 mCurrentUpstreamIfaceSet);
                         // If there has been a change and an upstream is now
                         // desired, kick off the selection process.
@@ -1577,7 +1576,7 @@
                         break;
                     }
                     case EVENT_IFACE_SERVING_STATE_INACTIVE: {
-                        TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj;
+                        IpServer who = (IpServer) message.obj;
                         if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
                         handleInterfaceServingStateInactive(who);
 
@@ -1591,7 +1590,7 @@
                         if (DBG) {
                             Log.d(TAG, "TetherModeAlive still has " + mNotifyList.size() +
                                     " live requests:");
-                            for (TetherInterfaceStateMachine o : mNotifyList) {
+                            for (IpServer o : mNotifyList) {
                                 Log.d(TAG, "  " + o);
                             }
                         }
@@ -1605,7 +1604,7 @@
                     }
                     case EVENT_IFACE_UPDATE_LINKPROPERTIES: {
                         final LinkProperties newLp = (LinkProperties) message.obj;
-                        if (message.arg1 == IControlsTethering.STATE_TETHERED) {
+                        if (message.arg1 == IpServer.STATE_TETHERED) {
                             mOffload.updateDownstreamLinkProperties(newLp);
                         } else {
                             mOffload.excludeDownstreamInterface(newLp.getInterfaceName());
@@ -1650,7 +1649,7 @@
                 boolean retValue = true;
                 switch (message.what) {
                     case EVENT_IFACE_SERVING_STATE_ACTIVE:
-                        TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj;
+                        IpServer who = (IpServer) message.obj;
                         who.sendMessage(mErrorNotification);
                         break;
                     case CMD_CLEAR_ERROR:
@@ -1665,8 +1664,8 @@
 
             void notify(int msgType) {
                 mErrorNotification = msgType;
-                for (TetherInterfaceStateMachine sm : mNotifyList) {
-                    sm.sendMessage(msgType);
+                for (IpServer ipServer : mNotifyList) {
+                    ipServer.sendMessage(msgType);
                 }
             }
 
@@ -1676,7 +1675,7 @@
             @Override
             public void enter() {
                 Log.e(TAG, "Error in setIpForwardingEnabled");
-                notify(TetherInterfaceStateMachine.CMD_IP_FORWARDING_ENABLE_ERROR);
+                notify(IpServer.CMD_IP_FORWARDING_ENABLE_ERROR);
             }
         }
 
@@ -1684,7 +1683,7 @@
             @Override
             public void enter() {
                 Log.e(TAG, "Error in setIpForwardingDisabled");
-                notify(TetherInterfaceStateMachine.CMD_IP_FORWARDING_DISABLE_ERROR);
+                notify(IpServer.CMD_IP_FORWARDING_DISABLE_ERROR);
             }
         }
 
@@ -1692,7 +1691,7 @@
             @Override
             public void enter() {
                 Log.e(TAG, "Error in startTethering");
-                notify(TetherInterfaceStateMachine.CMD_START_TETHERING_ERROR);
+                notify(IpServer.CMD_START_TETHERING_ERROR);
                 try {
                     mNMService.setIpForwardingEnabled(false);
                 } catch (Exception e) {}
@@ -1703,7 +1702,7 @@
             @Override
             public void enter() {
                 Log.e(TAG, "Error in stopTethering");
-                notify(TetherInterfaceStateMachine.CMD_STOP_TETHERING_ERROR);
+                notify(IpServer.CMD_STOP_TETHERING_ERROR);
                 try {
                     mNMService.setIpForwardingEnabled(false);
                 } catch (Exception e) {}
@@ -1714,7 +1713,7 @@
             @Override
             public void enter() {
                 Log.e(TAG, "Error in setDnsForwarders");
-                notify(TetherInterfaceStateMachine.CMD_SET_DNS_FORWARDERS_ERROR);
+                notify(IpServer.CMD_SET_DNS_FORWARDERS_ERROR);
                 try {
                     mNMService.stopTethering();
                 } catch (Exception e) {}
@@ -1771,15 +1770,15 @@
 
                 // Maybe add prefixes or addresses for downstreams, depending on
                 // the IP serving mode of each.
-                for (TetherInterfaceStateMachine tism : mNotifyList) {
-                    final LinkProperties lp = tism.linkProperties();
+                for (IpServer ipServer : mNotifyList) {
+                    final LinkProperties lp = ipServer.linkProperties();
 
-                    switch (tism.servingMode()) {
-                        case IControlsTethering.STATE_UNAVAILABLE:
-                        case IControlsTethering.STATE_AVAILABLE:
+                    switch (ipServer.servingMode()) {
+                        case IpServer.STATE_UNAVAILABLE:
+                        case IpServer.STATE_AVAILABLE:
                             // No usable LinkProperties in these states.
                             continue;
-                        case IControlsTethering.STATE_TETHERED:
+                        case IpServer.STATE_TETHERED:
                             // Only add IPv4 /32 and IPv6 /128 prefixes. The
                             // directly-connected prefixes will be sent as
                             // downstream "offload-able" prefixes.
@@ -1789,7 +1788,7 @@
                                 localPrefixes.add(PrefixUtils.ipAddressAsPrefix(ip));
                             }
                             break;
-                        case IControlsTethering.STATE_LOCAL_ONLY:
+                        case IpServer.STATE_LOCAL_ONLY:
                             // Add prefixes covering all local IPs.
                             localPrefixes.addAll(PrefixUtils.localPrefixesFrom(lp));
                             break;
@@ -1826,16 +1825,16 @@
                 pw.print(iface + " - ");
 
                 switch (tetherState.lastState) {
-                    case IControlsTethering.STATE_UNAVAILABLE:
+                    case IpServer.STATE_UNAVAILABLE:
                         pw.print("UnavailableState");
                         break;
-                    case IControlsTethering.STATE_AVAILABLE:
+                    case IpServer.STATE_AVAILABLE:
                         pw.print("AvailableState");
                         break;
-                    case IControlsTethering.STATE_TETHERED:
+                    case IpServer.STATE_TETHERED:
                         pw.print("TetheredState");
                         break;
-                    case IControlsTethering.STATE_LOCAL_ONLY:
+                    case IpServer.STATE_LOCAL_ONLY:
                         pw.print("LocalHotspotState");
                         break;
                     default:
@@ -1873,28 +1872,26 @@
         return false;
     }
 
-    private IControlsTethering makeControlCallback(String ifname) {
-        return new IControlsTethering() {
+    private IpServer.Callback makeControlCallback() {
+        return new IpServer.Callback() {
             @Override
-            public void updateInterfaceState(
-                    TetherInterfaceStateMachine who, int state, int lastError) {
-                notifyInterfaceStateChange(ifname, who, state, lastError);
+            public void updateInterfaceState(IpServer who, int state, int lastError) {
+                notifyInterfaceStateChange(who, state, lastError);
             }
 
             @Override
-            public void updateLinkProperties(
-                    TetherInterfaceStateMachine who, LinkProperties newLp) {
-                notifyLinkPropertiesChanged(ifname, who, newLp);
+            public void updateLinkProperties(IpServer who, LinkProperties newLp) {
+                notifyLinkPropertiesChanged(who, newLp);
             }
         };
     }
 
     // TODO: Move into TetherMasterSM.
-    private void notifyInterfaceStateChange(
-            String iface, TetherInterfaceStateMachine who, int state, int error) {
+    private void notifyInterfaceStateChange(IpServer who, int state, int error) {
+        final String iface = who.interfaceName();
         synchronized (mPublicSync) {
             final TetherState tetherState = mTetherStates.get(iface);
-            if (tetherState != null && tetherState.stateMachine.equals(who)) {
+            if (tetherState != null && tetherState.ipServer.equals(who)) {
                 tetherState.lastState = state;
                 tetherState.lastError = error;
             } else {
@@ -1908,7 +1905,7 @@
             // Notify that we're tethering (or not) this interface.
             // This is how data saver for instance knows if the user explicitly
             // turned on tethering (thus keeping us from being in data saver mode).
-            mPolicyManager.onTetheringChanged(iface, state == IControlsTethering.STATE_TETHERED);
+            mPolicyManager.onTetheringChanged(iface, state == IpServer.STATE_TETHERED);
         } catch (RemoteException e) {
             // Not really very much we can do here.
         }
@@ -1921,12 +1918,12 @@
         }
         int which;
         switch (state) {
-            case IControlsTethering.STATE_UNAVAILABLE:
-            case IControlsTethering.STATE_AVAILABLE:
+            case IpServer.STATE_UNAVAILABLE:
+            case IpServer.STATE_AVAILABLE:
                 which = TetherMasterSM.EVENT_IFACE_SERVING_STATE_INACTIVE;
                 break;
-            case IControlsTethering.STATE_TETHERED:
-            case IControlsTethering.STATE_LOCAL_ONLY:
+            case IpServer.STATE_TETHERED:
+            case IpServer.STATE_LOCAL_ONLY:
                 which = TetherMasterSM.EVENT_IFACE_SERVING_STATE_ACTIVE;
                 break;
             default:
@@ -1937,12 +1934,12 @@
         sendTetherStateChangedBroadcast();
     }
 
-    private void notifyLinkPropertiesChanged(String iface, TetherInterfaceStateMachine who,
-                                             LinkProperties newLp) {
+    private void notifyLinkPropertiesChanged(IpServer who, LinkProperties newLp) {
+        final String iface = who.interfaceName();
         final int state;
         synchronized (mPublicSync) {
             final TetherState tetherState = mTetherStates.get(iface);
-            if (tetherState != null && tetherState.stateMachine.equals(who)) {
+            if (tetherState != null && tetherState.ipServer.equals(who)) {
                 state = tetherState.lastState;
             } else {
                 mLog.log("got notification from stale iface " + iface);
@@ -1952,7 +1949,7 @@
 
         mLog.log(String.format(
                 "OBSERVED LinkProperties update iface=%s state=%s lp=%s",
-                iface, IControlsTethering.getStateString(state), newLp));
+                iface, IpServer.getStateString(state), newLp));
         final int which = TetherMasterSM.EVENT_IFACE_UPDATE_LINKPROPERTIES;
         mTetherMasterSM.sendMessage(which, state, 0, newLp);
     }
@@ -1976,11 +1973,11 @@
 
         mLog.log("adding TetheringInterfaceStateMachine for: " + iface);
         final TetherState tetherState = new TetherState(
-                new TetherInterfaceStateMachine(
-                    iface, mLooper, interfaceType, mLog, mNMService, mStatsService,
-                    makeControlCallback(iface), mConfig.enableLegacyDhcpServer, mDeps));
+                new IpServer(iface, mLooper, interfaceType, mLog, mNMService, mStatsService,
+                             makeControlCallback(), mConfig.enableLegacyDhcpServer,
+                             mDeps.getIpServerDependencies()));
         mTetherStates.put(iface, tetherState);
-        tetherState.stateMachine.start();
+        tetherState.ipServer.start();
     }
 
     private void stopTrackingInterfaceLocked(final String iface) {
@@ -1989,36 +1986,11 @@
             mLog.log("attempting to remove unknown iface (" + iface + "), ignoring");
             return;
         }
-        tetherState.stateMachine.stop();
+        tetherState.ipServer.stop();
         mLog.log("removing TetheringInterfaceStateMachine for: " + iface);
         mTetherStates.remove(iface);
     }
 
-    private static String getIPv4DefaultRouteInterface(NetworkState ns) {
-        if (ns == null) return null;
-        return getInterfaceForDestination(ns.linkProperties, Inet4Address.ANY);
-    }
-
-    private static String getIPv6DefaultRouteInterface(NetworkState ns) {
-        if (ns == null) return null;
-        // An upstream network's IPv6 capability is currently only useful if it
-        // can be 64share'd downstream (RFC 7278). For now, that means mobile
-        // upstream networks only.
-        if (ns.networkCapabilities == null ||
-                !ns.networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
-            return null;
-        }
-
-        return getInterfaceForDestination(ns.linkProperties, Inet6Address.ANY);
-    }
-
-    private static String getInterfaceForDestination(LinkProperties lp, InetAddress dst) {
-        final RouteInfo ri = (lp != null)
-                ? RouteInfo.selectBestRoute(lp.getAllRoutes(), dst)
-                : null;
-        return (ri != null) ? ri.getInterface() : null;
-    }
-
     private static String[] copy(String[] strarray) {
         return Arrays.copyOf(strarray, strarray.length);
     }
diff --git a/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java b/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java
deleted file mode 100644
index 2b81347..0000000
--- a/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity.tethering;
-
-import android.net.LinkProperties;
-
-/**
- * @hide
- *
- * Interface with methods necessary to notify that a given interface is ready for tethering.
- *
- * Rename to something more representative, e.g. IpServingControlCallback.
- *
- * All methods MUST be called on the TetherMasterSM main Looper's thread.
- */
-public class IControlsTethering {
-    public static final int STATE_UNAVAILABLE = 0;
-    public static final int STATE_AVAILABLE   = 1;
-    public static final int STATE_TETHERED    = 2;
-    public static final int STATE_LOCAL_ONLY  = 3;
-
-    public static String getStateString(int state) {
-        switch (state) {
-            case STATE_UNAVAILABLE: return "UNAVAILABLE";
-            case STATE_AVAILABLE:   return "AVAILABLE";
-            case STATE_TETHERED:    return "TETHERED";
-            case STATE_LOCAL_ONLY:  return "LOCAL_ONLY";
-        }
-        return "UNKNOWN: " + state;
-    }
-
-    /**
-     * Notify that |who| has changed its tethering state.
-     *
-     * TODO: Remove the need for the |who| argument.
-     *
-     * @param who corresponding instance of a TetherInterfaceStateMachine
-     * @param state one of IControlsTethering.STATE_*
-     * @param lastError one of ConnectivityManager.TETHER_ERROR_*
-     */
-    public void updateInterfaceState(TetherInterfaceStateMachine who, int state, int lastError) {}
-
-    /**
-     * Notify that |who| has new LinkProperties.
-     *
-     * TODO: Remove the need for the |who| argument.
-     *
-     * @param who corresponding instance of a TetherInterfaceStateMachine
-     * @param newLp the new LinkProperties to report
-     */
-    public void updateLinkProperties(TetherInterfaceStateMachine who, LinkProperties newLp) {}
-}
diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
index ba67c94..1000148 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
@@ -17,6 +17,7 @@
 package com.android.server.connectivity.tethering;
 
 import android.net.ConnectivityManager;
+import android.net.ip.IpServer;
 import android.net.IpPrefix;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
@@ -50,19 +51,19 @@
     private static final boolean VDBG = false;
 
     private static class Downstream {
-        public final TetherInterfaceStateMachine tism;
-        public final int mode;  // IControlsTethering.STATE_*
+        public final IpServer ipServer;
+        public final int mode;  // IpServer.STATE_*
         // Used to append to a ULA /48, constructing a ULA /64 for local use.
         public final short subnetId;
 
-        Downstream(TetherInterfaceStateMachine tism, int mode, short subnetId) {
-            this.tism = tism;
+        Downstream(IpServer ipServer, int mode, short subnetId) {
+            this.ipServer = ipServer;
             this.mode = mode;
             this.subnetId = subnetId;
         }
     }
 
-    private final ArrayList<TetherInterfaceStateMachine> mNotifyList;
+    private final ArrayList<IpServer> mNotifyList;
     private final SharedLog mLog;
     // NOTE: mActiveDownstreams is a list and not a hash data structure because
     // we keep active downstreams in arrival order.  This is done so /64s can
@@ -74,8 +75,7 @@
     private short mNextSubnetId;
     private NetworkState mUpstreamNetworkState;
 
-    public IPv6TetheringCoordinator(ArrayList<TetherInterfaceStateMachine> notifyList,
-                                    SharedLog log) {
+    public IPv6TetheringCoordinator(ArrayList<IpServer> notifyList, SharedLog log) {
         mNotifyList = notifyList;
         mLog = log.forSubComponent(TAG);
         mActiveDownstreams = new LinkedList<>();
@@ -83,7 +83,7 @@
         mNextSubnetId = 0;
     }
 
-    public void addActiveDownstream(TetherInterfaceStateMachine downstream, int mode) {
+    public void addActiveDownstream(IpServer downstream, int mode) {
         if (findDownstream(downstream) == null) {
             // Adding a new downstream appends it to the list. Adding a
             // downstream a second time without first removing it has no effect.
@@ -98,7 +98,7 @@
         }
     }
 
-    public void removeActiveDownstream(TetherInterfaceStateMachine downstream) {
+    public void removeActiveDownstream(IpServer downstream) {
         stopIPv6TetheringOn(downstream);
         if (mActiveDownstreams.remove(findDownstream(downstream))) {
             updateIPv6TetheringInterfaces();
@@ -133,8 +133,8 @@
     }
 
     private void stopIPv6TetheringOnAllInterfaces() {
-        for (TetherInterfaceStateMachine sm : mNotifyList) {
-            stopIPv6TetheringOn(sm);
+        for (IpServer ipServer : mNotifyList) {
+            stopIPv6TetheringOn(ipServer);
         }
     }
 
@@ -156,28 +156,28 @@
     }
 
     private void updateIPv6TetheringInterfaces() {
-        for (TetherInterfaceStateMachine sm : mNotifyList) {
-            final LinkProperties lp = getInterfaceIPv6LinkProperties(sm);
-            sm.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0, lp);
+        for (IpServer ipServer : mNotifyList) {
+            final LinkProperties lp = getInterfaceIPv6LinkProperties(ipServer);
+            ipServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, lp);
             break;
         }
     }
 
-    private LinkProperties getInterfaceIPv6LinkProperties(TetherInterfaceStateMachine sm) {
-        if (sm.interfaceType() == ConnectivityManager.TETHERING_BLUETOOTH) {
+    private LinkProperties getInterfaceIPv6LinkProperties(IpServer ipServer) {
+        if (ipServer.interfaceType() == ConnectivityManager.TETHERING_BLUETOOTH) {
             // TODO: Figure out IPv6 support on PAN interfaces.
             return null;
         }
 
-        final Downstream ds = findDownstream(sm);
+        final Downstream ds = findDownstream(ipServer);
         if (ds == null) return null;
 
-        if (ds.mode == IControlsTethering.STATE_LOCAL_ONLY) {
+        if (ds.mode == IpServer.STATE_LOCAL_ONLY) {
             // Build a Unique Locally-assigned Prefix configuration.
             return getUniqueLocalConfig(mUniqueLocalPrefix, ds.subnetId);
         }
 
-        // This downstream is in IControlsTethering.STATE_TETHERED mode.
+        // This downstream is in IpServer.STATE_TETHERED mode.
         if (mUpstreamNetworkState == null || mUpstreamNetworkState.linkProperties == null) {
             return null;
         }
@@ -188,7 +188,7 @@
         // IPv6 toward the oldest (first requested) active downstream.
 
         final Downstream currentActive = mActiveDownstreams.peek();
-        if (currentActive != null && currentActive.tism == sm) {
+        if (currentActive != null && currentActive.ipServer == ipServer) {
             final LinkProperties lp = getIPv6OnlyLinkProperties(
                     mUpstreamNetworkState.linkProperties);
             if (lp.hasIPv6DefaultRoute() && lp.hasGlobalIPv6Address()) {
@@ -199,9 +199,9 @@
         return null;
     }
 
-    Downstream findDownstream(TetherInterfaceStateMachine tism) {
+    Downstream findDownstream(IpServer ipServer) {
         for (Downstream ds : mActiveDownstreams) {
-            if (ds.tism == tism) return ds;
+            if (ds.ipServer == ipServer) return ds;
         }
         return null;
     }
@@ -304,7 +304,7 @@
                 ns.linkProperties);
     }
 
-    private static void stopIPv6TetheringOn(TetherInterfaceStateMachine sm) {
-        sm.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0, null);
+    private static void stopIPv6TetheringOn(IpServer ipServer) {
+        ipServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, null);
     }
 }
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
index caa867c..8b40069 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
@@ -21,6 +21,7 @@
 import android.net.NetworkRequest;
 import android.net.dhcp.DhcpServer;
 import android.net.dhcp.DhcpServingParams;
+import android.net.ip.IpServer;
 import android.net.ip.RouterAdvertisementDaemon;
 import android.net.util.InterfaceParams;
 import android.net.util.NetdService;
@@ -49,20 +50,12 @@
     }
 
     public IPv6TetheringCoordinator getIPv6TetheringCoordinator(
-            ArrayList<TetherInterfaceStateMachine> notifyList, SharedLog log) {
+            ArrayList<IpServer> notifyList, SharedLog log) {
         return new IPv6TetheringCoordinator(notifyList, log);
     }
 
-    public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) {
-        return new RouterAdvertisementDaemon(ifParams);
-    }
-
-    public InterfaceParams getInterfaceParams(String ifName) {
-        return InterfaceParams.getByName(ifName);
-    }
-
-    public INetd getNetdService() {
-        return NetdService.getInstance();
+    public IpServer.Dependencies getIpServerDependencies() {
+        return new IpServer.Dependencies();
     }
 
     public boolean isTetheringSupported() {
@@ -72,9 +65,4 @@
     public NetworkRequest getDefaultNetworkRequest() {
         return null;
     }
-
-    public DhcpServer makeDhcpServer(Looper looper, InterfaceParams iface, DhcpServingParams params,
-            SharedLog log) {
-        return new DhcpServer(looper, iface, params, log);
-    }
 }
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index d8d650b..5698fdf 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -1226,7 +1226,7 @@
 
         if (userId == UserHandle.USER_ALL) {
             mContext.enforceCallingOrSelfPermission(
-                    Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG);
+                    Manifest.permission.INTERACT_ACROSS_USERS_FULL, "No access to " + uri);
         } else if (userId < 0) {
             throw new IllegalArgumentException("Invalid user: " + userId);
         } else if (userId != UserHandle.getCallingUserId()) {
@@ -1247,7 +1247,7 @@
                             ? (Manifest.permission.INTERACT_ACROSS_USERS_FULL + " or " +
                                     Manifest.permission.INTERACT_ACROSS_USERS)
                             : Manifest.permission.INTERACT_ACROSS_USERS_FULL;
-                    throw new SecurityException(TAG + "Neither user " + uid
+                    throw new SecurityException("No access to " + uri + ": neither user " + uid
                             + " nor current process has " + permissions);
                 }
             }
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java b/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java
index d4932f9..2fdcb51 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java
@@ -25,6 +25,9 @@
 
     // State that waits for <Active Source> once send <Request Active Source>.
     private static final int STATE_WAITING_FOR_ACTIVE_SOURCE = 1;
+    // State that waits for TV supporting Audio System Mode or not
+    // once received <Active Source>
+    private static final int STATE_WAITING_FOR_TV_SUPPORT = 2;
     @VisibleForTesting
     static final int MAX_RETRY_COUNT = 5;
 
@@ -60,6 +63,7 @@
                 if (physicalAddress != getSourcePath()) {
                     audioSystem().setActiveSource(cmd.getSource(), physicalAddress);
                 }
+                mState = STATE_WAITING_FOR_TV_SUPPORT;
                 queryTvSystemAudioModeSupport();
                 return true;
         }
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index a050aa9..0f28439 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -1875,30 +1875,36 @@
         // Read partner-provided list of excluded input devices
         XmlPullParser parser = null;
         // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
-        File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH);
-        FileReader confreader = null;
-        try {
-            confreader = new FileReader(confFile);
-            parser = Xml.newPullParser();
-            parser.setInput(confreader);
-            XmlUtils.beginDocument(parser, "devices");
+        final File[] baseDirs = {
+            Environment.getRootDirectory(),
+            Environment.getVendorDirectory()
+        };
+        for (File baseDir: baseDirs) {
+            File confFile = new File(baseDir, EXCLUDED_DEVICES_PATH);
+            FileReader confreader = null;
+            try {
+                confreader = new FileReader(confFile);
+                parser = Xml.newPullParser();
+                parser.setInput(confreader);
+                XmlUtils.beginDocument(parser, "devices");
 
-            while (true) {
-                XmlUtils.nextElement(parser);
-                if (!"device".equals(parser.getName())) {
-                    break;
+                while (true) {
+                    XmlUtils.nextElement(parser);
+                    if (!"device".equals(parser.getName())) {
+                        break;
+                    }
+                    String name = parser.getAttributeValue(null, "name");
+                    if (name != null) {
+                        names.add(name);
+                    }
                 }
-                String name = parser.getAttributeValue(null, "name");
-                if (name != null) {
-                    names.add(name);
-                }
+            } catch (FileNotFoundException e) {
+                // It's ok if the file does not exist.
+            } catch (Exception e) {
+                Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
+            } finally {
+                try { if (confreader != null) confreader.close(); } catch (IOException e) { }
             }
-        } catch (FileNotFoundException e) {
-            // It's ok if the file does not exist.
-        } catch (Exception e) {
-            Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
-        } finally {
-            try { if (confreader != null) confreader.close(); } catch (IOException e) { }
         }
 
         return names.toArray(new String[names.size()]);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
index b5a9f74..3264790 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
@@ -18,45 +18,11 @@
 
 import android.content.ComponentName;
 
-import com.android.internal.view.IInputContext;
-import com.android.internal.view.IInputMethodClient;
-
 /**
  * Input method manager local system service interface.
  */
 public abstract class InputMethodManagerInternal {
     /**
-     * Called by the window manager service when a client process is being attached to the window
-     * manager service.
-     *
-     * <p>The caller must not have WindowManagerService lock.  This method internally acquires
-     * InputMethodManagerService lock.</p>
-     *
-     * @param client {@link android.os.Binder} proxy that is associated with the singleton instance
-     *               of {@link android.view.inputmethod.InputMethodManager} that runs on the client
-     *               process
-     * @param inputContext communication channel for the dummy
-     *                     {@link android.view.inputmethod.InputConnection}
-     * @param uid UID of the client process
-     * @param pid PID of the client process
-     */
-    public abstract void addClient(IInputMethodClient client, IInputContext inputContext, int uid,
-            int pid);
-
-    /**
-     * Called by the window manager service when a client process is being attached to the window
-     * manager service.
-     *
-     * <p>The caller must not have WindowManagerService lock.  This method internally acquires
-     * InputMethodManagerService lock.</p>
-     *
-     * @param client {@link android.os.Binder} proxy that is associated with the singleton instance
-     *               of {@link android.view.inputmethod.InputMethodManager} that runs on the client
-     *               process
-     */
-    public abstract void removeClient(IInputMethodClient client);
-
-    /**
      * Called by the power manager to tell the input method manager whether it
      * should start watching for wake events.
      */
@@ -78,15 +44,6 @@
     public static final InputMethodManagerInternal NOP =
             new InputMethodManagerInternal() {
                 @Override
-                public void addClient(IInputMethodClient client, IInputContext inputContext,
-                        int uid, int pid) {
-                }
-
-                @Override
-                public void removeClient(IInputMethodClient client) {
-                }
-
-                @Override
                 public void setInteractive(boolean interactive) {
                 }
 
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 44fb9ea..a9b0d5c 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -130,10 +130,6 @@
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.inputmethod.IInputContentUriToken;
 import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
-import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController;
-import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
-import com.android.internal.inputmethod.InputMethodUtils;
-import com.android.internal.inputmethod.InputMethodUtils.InputMethodSettings;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.os.HandlerCaller;
@@ -153,6 +149,8 @@
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
+import com.android.server.inputmethod.InputMethodUtils.InputMethodSettings;
 import com.android.server.statusbar.StatusBarManagerService;
 import com.android.server.wm.WindowManagerInternal;
 
@@ -403,12 +401,28 @@
         }
     }
 
+    private static final class ClientDeathRecipient implements IBinder.DeathRecipient {
+        private final InputMethodManagerService mImms;
+        private final IInputMethodClient mClient;
+
+        ClientDeathRecipient(InputMethodManagerService imms, IInputMethodClient client) {
+            mImms = imms;
+            mClient = client;
+        }
+
+        @Override
+        public void binderDied() {
+            mImms.removeClient(mClient);
+        }
+    }
+
     static final class ClientState {
         final IInputMethodClient client;
         final IInputContext inputContext;
         final int uid;
         final int pid;
         final InputBinding binding;
+        final ClientDeathRecipient clientDeathRecipient;
 
         boolean sessionRequested;
         SessionState curSession;
@@ -421,12 +435,13 @@
         }
 
         ClientState(IInputMethodClient _client, IInputContext _inputContext,
-                int _uid, int _pid) {
+                int _uid, int _pid, ClientDeathRecipient _clientDeathRecipient) {
             client = _client;
             inputContext = _inputContext;
             uid = _uid;
             pid = _pid;
             binding = new InputBinding(null, inputContext.asBinder(), uid, pid);
+            clientDeathRecipient = _clientDeathRecipient;
         }
     }
 
@@ -1718,9 +1733,39 @@
         }
     }
 
-    void addClient(ClientState clientState) {
+    /**
+     * Called by each application process as a preparation to start interacting with
+     * {@link InputMethodManagerService}.
+     *
+     * <p>As a general principle, IPCs from the application process that take
+     * {@link InputMethodClient} will be rejected without this step.</p>
+     *
+     * @param client {@link android.os.Binder} proxy that is associated with the singleton instance
+     *               of {@link android.view.inputmethod.InputMethodManager} that runs on the client
+     *               process
+     * @param inputContext communication channel for the dummy
+     *                     {@link android.view.inputmethod.InputConnection}
+     */
+    @Override
+    public void addClient(IInputMethodClient client, IInputContext inputContext) {
+        final int callerUid = Binder.getCallingUid();
+        final int callerPid = Binder.getCallingPid();
         synchronized (mMethodMap) {
-            mClients.put(clientState.client.asBinder(), clientState);
+            // TODO: Optimize this linear search.
+            for (ClientState state : mClients.values()) {
+                if (state.uid == callerUid && state.pid == callerPid) {
+                    throw new SecurityException("uid=" + callerUid + "/pid=" + callerPid
+                            + " is already registered");
+                }
+            }
+            final ClientDeathRecipient deathRecipient = new ClientDeathRecipient(this, client);
+            try {
+                client.asBinder().linkToDeath(deathRecipient, 0);
+            } catch (RemoteException e) {
+                throw new IllegalStateException(e);
+            }
+            mClients.put(client.asBinder(),
+                    new ClientState(client, inputContext, callerUid, callerPid, deathRecipient));
         }
     }
 
@@ -1728,6 +1773,7 @@
         synchronized (mMethodMap) {
             ClientState cs = mClients.remove(client.asBinder());
             if (cs != null) {
+                client.asBinder().unlinkToDeath(cs.clientDeathRecipient, 0);
                 clearClientSessionLocked(cs);
                 if (mCurClient == cs) {
                     if (mBoundToMethod) {
@@ -1930,7 +1976,7 @@
             throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
         }
 
-        unbindCurrentMethodLocked(true);
+        unbindCurrentMethodLocked();
 
         mCurIntent = new Intent(InputMethod.SERVICE_INTERFACE);
         mCurIntent.setComponent(info.getComponent());
@@ -1974,7 +2020,7 @@
                 mCurMethod = IInputMethod.Stub.asInterface(service);
                 if (mCurToken == null) {
                     Slog.w(TAG, "Service connected without a token!");
-                    unbindCurrentMethodLocked(false);
+                    unbindCurrentMethodLocked();
                     return;
                 }
                 if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
@@ -2013,7 +2059,7 @@
         channel.dispose();
     }
 
-    void unbindCurrentMethodLocked(boolean savePosition) {
+    void unbindCurrentMethodLocked() {
         if (mVisibleBound) {
             mContext.unbindService(mVisibleConnection);
             mVisibleBound = false;
@@ -2030,10 +2076,6 @@
                     Slog.v(TAG, "Removing window token: " + mCurToken + " for display: "
                             + mCurTokenDisplayId);
                 }
-                if ((mImeWindowVis & InputMethodService.IME_ACTIVE) != 0 && savePosition) {
-                    // The current IME is shown. Hence an IME switch (transition) is happening.
-                    mWindowManagerInternal.saveLastInputMethodWindowForTransition();
-                }
                 mIWindowManager.removeWindowToken(mCurToken, mCurTokenDisplayId);
             } catch (RemoteException e) {
             }
@@ -2048,7 +2090,7 @@
     void resetCurrentMethodAndClient(
             /* @InputMethodClient.UnbindReason */ final int unbindClientReason) {
         mCurMethodId = null;
-        unbindCurrentMethodLocked(false);
+        unbindCurrentMethodLocked();
         unbindCurrentClientLocked(unbindClientReason);
     }
 
@@ -2538,7 +2580,11 @@
                     // We need to check if this is the current client with
                     // focus in the window manager, to allow this call to
                     // be made before input is started in it.
-                    if (!mWindowManagerInternal.inputMethodClientHasFocus(client)) {
+                    final ClientState cs = mClients.get(client.asBinder());
+                    if (cs == null) {
+                        throw new IllegalArgumentException("unknown client " + client.asBinder());
+                    }
+                    if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid)) {
                         Slog.w(TAG, "Ignoring showSoftInput of uid " + uid + ": " + client);
                         return false;
                     }
@@ -2618,7 +2664,11 @@
                     // We need to check if this is the current client with
                     // focus in the window manager, to allow this call to
                     // be made before input is started in it.
-                    if (!mWindowManagerInternal.inputMethodClientHasFocus(client)) {
+                    final ClientState cs = mClients.get(client.asBinder());
+                    if (cs == null) {
+                        throw new IllegalArgumentException("unknown client " + client.asBinder());
+                    }
+                    if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid)) {
                         if (DEBUG) {
                             Slog.w(TAG, "Ignoring hideSoftInput of uid " + uid + ": " + client);
                         }
@@ -2736,7 +2786,7 @@
                             + client.asBinder());
                 }
 
-                if (!mWindowManagerInternal.inputMethodClientHasFocus(cs.client)) {
+                if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid)) {
                     // Check with the window manager to make sure this client actually
                     // has a window with focus.  If not, reject.  This is thread safe
                     // because if the focus changes some time before or after, the
@@ -2811,7 +2861,7 @@
                                 final int newFocusDisplayId =
                                         mWindowManagerInternal.getDisplayIdForWindow(windowToken);
                                 if (newFocusDisplayId != mCurTokenDisplayId) {
-                                    unbindCurrentMethodLocked(false);
+                                    unbindCurrentMethodLocked();
                                 }
                             }
                         } else if (isTextEditor && doAutoShow && (softInputMode &
@@ -3183,19 +3233,6 @@
     }
 
     @BinderThread
-    private void clearLastInputMethodWindowForTransition(IBinder token) {
-        if (!calledFromValidUser()) {
-            return;
-        }
-        synchronized (mMethodMap) {
-            if (!calledWithValidToken(token)) {
-                return;
-            }
-        }
-        mWindowManagerInternal.clearLastInputMethodWindowForTransition();
-    }
-
-    @BinderThread
     private void notifyUserAction(@NonNull IBinder token) {
         if (DEBUG) {
             Slog.d(TAG, "Got the notification of a user action.");
@@ -4401,20 +4438,6 @@
         }
 
         @Override
-        public void addClient(IInputMethodClient client, IInputContext inputContext, int uid,
-                int pid) {
-            // Work around Bug 113877122: We need to handle this synchronously.  Otherwise, some
-            // IMM binder calls from the client process before we register this client.
-            mService.addClient(new ClientState(client, inputContext, uid, pid));
-        }
-
-        @Override
-        public void removeClient(IInputMethodClient client) {
-            // Handle this synchronously to be consistent with addClient().
-            mService.removeClient(client);
-        }
-
-        @Override
         public void setInteractive(boolean interactive) {
             // Do everything in handler so as not to block the caller.
             mService.mHandler.obtainMessage(MSG_SET_INTERACTIVE, interactive ? 1 : 0, 0)
@@ -4917,7 +4940,7 @@
             try {
                 synchronized (mMethodMap) {
                     hideCurrentInputLocked(0, null);
-                    unbindCurrentMethodLocked(false);
+                    unbindCurrentMethodLocked();
                     // Reset the current IME
                     resetSelectedInputMethodAndSubtypeLocked(null);
                     // Also reset the settings of the current IME
@@ -4990,12 +5013,6 @@
 
         @BinderThread
         @Override
-        public void clearLastInputMethodWindowForTransition() {
-            mImms.clearLastInputMethodWindowForTransition(mToken);
-        }
-
-        @BinderThread
-        @Override
         public IInputContentUriToken createInputContentUriToken(Uri contentUri,
                 String packageName) {
             return mImms.createInputContentUriToken(mToken, contentUri, packageName);
diff --git a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java b/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
similarity index 98%
rename from core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
rename to services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
index 14ac2f6..77b2fee 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.inputmethod;
+package com.android.server.inputmethod;
 
 import android.annotation.Nullable;
 import android.content.Context;
@@ -27,7 +27,7 @@
 import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.inputmethod.InputMethodUtils.InputMethodSettings;
+import com.android.server.inputmethod.InputMethodUtils.InputMethodSettings;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -41,13 +41,11 @@
 
 /**
  * InputMethodSubtypeSwitchingController controls the switching behavior of the subtypes.
- * <p>
- * This class is designed to be used from and only from
- * {@link com.android.server.InputMethodManagerService} by using
- * {@link com.android.server.InputMethodManagerService#mMethodMap} as a global lock.
- * </p>
+ *
+ * <p>This class is designed to be used from and only from {@link InputMethodManagerService} by
+ * using {@link InputMethodManagerService#mMethodMap} as a global lock.</p>
  */
-public class InputMethodSubtypeSwitchingController {
+final class InputMethodSubtypeSwitchingController {
     private static final String TAG = InputMethodSubtypeSwitchingController.class.getSimpleName();
     private static final boolean DEBUG = false;
     private static final int NOT_A_SUBTYPE_ID = InputMethodUtils.NOT_A_SUBTYPE_ID;
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
similarity index 88%
rename from core/java/com/android/internal/inputmethod/InputMethodUtils.java
rename to services/core/java/com/android/server/inputmethod/InputMethodUtils.java
index 1e5b5c8..e951b27 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.inputmethod;
+package com.android.server.inputmethod;
 
 import static android.view.inputmethod.InputMethodManager.CONTROL_WINDOW_IS_TEXT_EDITOR;
 import static android.view.inputmethod.InputMethodManager.CONTROL_WINDOW_VIEW_HAS_FOCUS;
@@ -53,10 +53,14 @@
 import java.util.Locale;
 
 /**
- * InputMethodManagerUtils contains some static methods that provides IME informations.
- * This methods are supposed to be used in both the framework and the Settings application.
+ * This class provides random static utility methods for {@link InputMethodManagerService} and its
+ * utility classes.
+ *
+ * <p>This class is intentionally package-private.  Utility methods here are tightly coupled with
+ * implementation details in {@link InputMethodManagerService}.  Hence this class is not suitable
+ * for other components to directly use.</p>
  */
-public class InputMethodUtils {
+final class InputMethodUtils {
     public static final boolean DEBUG = false;
     public static final int NOT_A_SUBTYPE_ID = -1;
     public static final String SUBTYPE_MODE_ANY = null;
@@ -334,32 +338,6 @@
         return getDefaultEnabledImes(context, imis, false /* onlyMinimum */);
     }
 
-    public static Locale constructLocaleFromString(String localeStr) {
-        if (TextUtils.isEmpty(localeStr)) {
-            return null;
-        }
-        // TODO: Use {@link Locale#toLanguageTag()} and {@link Locale#forLanguageTag(languageTag)}.
-        String[] localeParams = localeStr.split("_", 3);
-        if (localeParams.length >= 1 && "tl".equals(localeParams[0])) {
-             // Convert a locale whose language is "tl" to one whose language is "fil".
-             // For example, "tl_PH" will get converted to "fil_PH".
-             // Versions of Android earlier than Lollipop did not support three letter language
-             // codes, and used "tl" (Tagalog) as the language string for "fil" (Filipino).
-             // On Lollipop and above, the current three letter version must be used.
-             localeParams[0] = "fil";
-        }
-        // The length of localeStr is guaranteed to always return a 1 <= value <= 3
-        // because localeStr is not empty.
-        if (localeParams.length == 1) {
-            return new Locale(localeParams[0]);
-        } else if (localeParams.length == 2) {
-            return new Locale(localeParams[0], localeParams[1]);
-        } else if (localeParams.length == 3) {
-            return new Locale(localeParams[0], localeParams[1], localeParams[2]);
-        }
-        return null;
-    }
-
     public static boolean containsSubtypeOf(final InputMethodInfo imi,
             @Nullable final Locale locale, final boolean checkCountry, final String mode) {
         if (locale == null) {
@@ -1320,133 +1298,6 @@
         }
     }
 
-    // For spell checker service manager.
-    // TODO: Should we have TextServicesUtils.java?
-    private static final Locale LOCALE_EN_US = new Locale("en", "US");
-    private static final Locale LOCALE_EN_GB = new Locale("en", "GB");
-
-    /**
-     * Returns a list of {@link Locale} in the order of appropriateness for the default spell
-     * checker service.
-     *
-     * <p>If the system language is English, and the region is also explicitly specified in the
-     * system locale, the following fallback order will be applied.</p>
-     * <ul>
-     * <li>(system-locale-language, system-locale-region, system-locale-variant) (if exists)</li>
-     * <li>(system-locale-language, system-locale-region)</li>
-     * <li>("en", "US")</li>
-     * <li>("en", "GB")</li>
-     * <li>("en")</li>
-     * </ul>
-     *
-     * <p>If the system language is English, but no region is specified in the system locale,
-     * the following fallback order will be applied.</p>
-     * <ul>
-     * <li>("en")</li>
-     * <li>("en", "US")</li>
-     * <li>("en", "GB")</li>
-     * </ul>
-     *
-     * <p>If the system language is not English, the following fallback order will be applied.</p>
-     * <ul>
-     * <li>(system-locale-language, system-locale-region, system-locale-variant) (if exists)</li>
-     * <li>(system-locale-language, system-locale-region) (if exists)</li>
-     * <li>(system-locale-language) (if exists)</li>
-     * <li>("en", "US")</li>
-     * <li>("en", "GB")</li>
-     * <li>("en")</li>
-     * </ul>
-     *
-     * @param systemLocale the current system locale to be taken into consideration.
-     * @return a list of {@link Locale}. The first one is considered to be most appropriate.
-     */
-    @VisibleForTesting
-    public static ArrayList<Locale> getSuitableLocalesForSpellChecker(
-            @Nullable final Locale systemLocale) {
-        final Locale systemLocaleLanguageCountryVariant;
-        final Locale systemLocaleLanguageCountry;
-        final Locale systemLocaleLanguage;
-        if (systemLocale != null) {
-            final String language = systemLocale.getLanguage();
-            final boolean hasLanguage = !TextUtils.isEmpty(language);
-            final String country = systemLocale.getCountry();
-            final boolean hasCountry = !TextUtils.isEmpty(country);
-            final String variant = systemLocale.getVariant();
-            final boolean hasVariant = !TextUtils.isEmpty(variant);
-            if (hasLanguage && hasCountry && hasVariant) {
-                systemLocaleLanguageCountryVariant = new Locale(language, country, variant);
-            } else {
-                systemLocaleLanguageCountryVariant = null;
-            }
-            if (hasLanguage && hasCountry) {
-                systemLocaleLanguageCountry = new Locale(language, country);
-            } else {
-                systemLocaleLanguageCountry = null;
-            }
-            if (hasLanguage) {
-                systemLocaleLanguage = new Locale(language);
-            } else {
-                systemLocaleLanguage = null;
-            }
-        } else {
-            systemLocaleLanguageCountryVariant = null;
-            systemLocaleLanguageCountry = null;
-            systemLocaleLanguage = null;
-        }
-
-        final ArrayList<Locale> locales = new ArrayList<>();
-        if (systemLocaleLanguageCountryVariant != null) {
-            locales.add(systemLocaleLanguageCountryVariant);
-        }
-
-        if (Locale.ENGLISH.equals(systemLocaleLanguage)) {
-            if (systemLocaleLanguageCountry != null) {
-                // If the system language is English, and the region is also explicitly specified,
-                // following fallback order will be applied.
-                // - systemLocaleLanguageCountry [if systemLocaleLanguageCountry is non-null]
-                // - en_US [if systemLocaleLanguageCountry is non-null and not en_US]
-                // - en_GB [if systemLocaleLanguageCountry is non-null and not en_GB]
-                // - en
-                if (systemLocaleLanguageCountry != null) {
-                    locales.add(systemLocaleLanguageCountry);
-                }
-                if (!LOCALE_EN_US.equals(systemLocaleLanguageCountry)) {
-                    locales.add(LOCALE_EN_US);
-                }
-                if (!LOCALE_EN_GB.equals(systemLocaleLanguageCountry)) {
-                    locales.add(LOCALE_EN_GB);
-                }
-                locales.add(Locale.ENGLISH);
-            } else {
-                // If the system language is English, but no region is specified, following
-                // fallback order will be applied.
-                // - en
-                // - en_US
-                // - en_GB
-                locales.add(Locale.ENGLISH);
-                locales.add(LOCALE_EN_US);
-                locales.add(LOCALE_EN_GB);
-            }
-        } else {
-            // If the system language is not English, the fallback order will be
-            // - systemLocaleLanguageCountry  [if non-null]
-            // - systemLocaleLanguage  [if non-null]
-            // - en_US
-            // - en_GB
-            // - en
-            if (systemLocaleLanguageCountry != null) {
-                locales.add(systemLocaleLanguageCountry);
-            }
-            if (systemLocaleLanguage != null) {
-                locales.add(systemLocaleLanguage);
-            }
-            locales.add(LOCALE_EN_US);
-            locales.add(LOCALE_EN_GB);
-            locales.add(Locale.ENGLISH);
-        }
-        return locales;
-    }
-
     public static boolean isSoftInputModeStateVisibleAllowed(
             int targetSdkVersion, int controlFlags) {
         if (targetSdkVersion < Build.VERSION_CODES.P) {
diff --git a/core/java/com/android/internal/inputmethod/LocaleUtils.java b/services/core/java/com/android/server/inputmethod/LocaleUtils.java
similarity index 97%
rename from core/java/com/android/internal/inputmethod/LocaleUtils.java
rename to services/core/java/com/android/server/inputmethod/LocaleUtils.java
index eeb3854..4958ece 100644
--- a/core/java/com/android/internal/inputmethod/LocaleUtils.java
+++ b/services/core/java/com/android/server/inputmethod/LocaleUtils.java
@@ -14,9 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.inputmethod;
-
-import com.android.internal.annotations.VisibleForTesting;
+package com.android.server.inputmethod;
 
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -31,9 +29,7 @@
 import java.util.List;
 import java.util.Locale;
 
-public final class LocaleUtils {
-
-    @VisibleForTesting
+final class LocaleUtils {
     public interface LocaleExtractor<T> {
         @Nullable
         Locale get(@Nullable T source);
@@ -149,7 +145,6 @@
      * @param dest Destination into which the filtered items will be added.
      * @param <T> Type of the data items.
      */
-    @VisibleForTesting
     public static <T> void filterByLanguage(
             @NonNull List<T> sources,
             @NonNull LocaleExtractor<T> extractor,
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 7751f5f..d326c22 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -20,6 +20,7 @@
 import static android.content.Context.BIND_AUTO_CREATE;
 import static android.content.Context.BIND_FOREGROUND_SERVICE;
 import static android.content.Context.DEVICE_POLICY_SERVICE;
+import static android.os.UserHandle.USER_ALL;
 
 import android.annotation.NonNull;
 import android.app.ActivityManager;
@@ -53,12 +54,15 @@
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.IntArray;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.proto.ProtoOutputStream;
 
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.XmlUtils;
 import com.android.server.notification.NotificationManagerService.DumpFilter;
 
@@ -72,6 +76,7 @@
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 import java.util.function.Predicate;
 
@@ -138,10 +143,6 @@
     // not mean that we are currently bound to said package/component.
     private ArrayMap<Integer, ArrayMap<Boolean, ArraySet<String>>> mApproved = new ArrayMap<>();
 
-    // Kept to de-dupe user change events (experienced after boot, when we receive a settings and a
-    // user change).
-    private int[] mLastSeenProfileIds;
-
     // True if approved services are stored in xml, not settings.
     private boolean mUseXml;
 
@@ -178,6 +179,10 @@
         }
     }
 
+    protected int getBindFlags() {
+        return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE | BIND_ALLOW_WHITELIST_MANAGEMENT;
+    }
+
     protected void onServiceRemovedLocked(ManagedServiceInfo removed) { }
 
     private ManagedServiceInfo newServiceInfo(IInterface service,
@@ -296,7 +301,7 @@
                 Settings.Secure.putStringForUser(
                         mContext.getContentResolver(), element, value, userId);
                 loadAllowedComponentsFromSettings();
-                rebindServices(false);
+                rebindServices(false, userId);
             }
         }
     }
@@ -381,7 +386,7 @@
                 }
             }
         }
-        rebindServices(false);
+        rebindServices(false, USER_ALL);
     }
 
     protected void upgradeXml(final int xmlVersion, final int userId) {}
@@ -456,7 +461,7 @@
             }
         }
 
-        rebindServices(false);
+        rebindServices(false, userId);
     }
 
     private String getApprovedValue(String pkgOrComponent) {
@@ -574,7 +579,7 @@
 
             if (anyServicesInvolved) {
                 // make sure we're still bound to any of our services who may have just upgraded
-                rebindServices(false);
+                rebindServices(false, USER_ALL);
             }
         }
     }
@@ -582,21 +587,17 @@
     public void onUserRemoved(int user) {
         Slog.i(TAG, "Removing approved services for removed user " + user);
         mApproved.remove(user);
-        rebindServices(true);
+        rebindServices(true, user);
     }
 
     public void onUserSwitched(int user) {
         if (DEBUG) Slog.d(TAG, "onUserSwitched u=" + user);
-        if (Arrays.equals(mLastSeenProfileIds, mUserProfiles.getCurrentProfileIds())) {
-            if (DEBUG) Slog.d(TAG, "Current profile IDs didn't change, skipping rebindServices().");
-            return;
-        }
-        rebindServices(true);
+        rebindServices(true, user);
     }
 
     public void onUserUnlocked(int user) {
         if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
-        rebindServices(false);
+        rebindServices(false, user);
     }
 
     private ManagedServiceInfo getServiceFromTokenLocked(IInterface service) {
@@ -690,9 +691,10 @@
                 component.flattenToShortString());
 
         synchronized (mMutex) {
-            final int[] userIds = mUserProfiles.getCurrentProfileIds();
+            final IntArray userIds = mUserProfiles.getCurrentProfileIds();
 
-            for (int userId : userIds) {
+            for (int i = 0; i < userIds.size(); i++) {
+                final int userId = userIds.get(i);
                 if (enabled) {
                     if (isPackageOrComponentAllowed(component.toString(), userId)
                             || isPackageOrComponentAllowed(component.getPackageName(), userId)) {
@@ -834,20 +836,14 @@
         return false;
     }
 
-    /**
-     * Called whenever packages change, the user switches, or the secure setting
-     * is altered. (For example in response to USER_SWITCHED in our broadcast receiver)
-     */
-    protected void rebindServices(boolean forceRebind) {
-        if (DEBUG) Slog.d(TAG, "rebindServices");
-        final int[] userIds = mUserProfiles.getCurrentProfileIds();
-        final int nUserIds = userIds.length;
-
+    @VisibleForTesting
+    protected SparseArray<ArraySet<ComponentName>> getAllowedComponents(IntArray userIds) {
+        final int nUserIds = userIds.size();
         final SparseArray<ArraySet<ComponentName>> componentsByUser = new SparseArray<>();
 
         for (int i = 0; i < nUserIds; ++i) {
-            final int userId = userIds[i];
-            final ArrayMap<Boolean, ArraySet<String>> approvedLists = mApproved.get(userIds[i]);
+            final int userId = userIds.get(i);
+            final ArrayMap<Boolean, ArraySet<String>> approvedLists = mApproved.get(userId);
             if (approvedLists != null) {
                 final int N = approvedLists.size();
                 for (int j = 0; j < N; j++) {
@@ -861,67 +857,125 @@
                 }
             }
         }
+        return componentsByUser;
+    }
 
-        final ArrayList<ManagedServiceInfo> removableBoundServices = new ArrayList<>();
-        final SparseArray<Set<ComponentName>> toAdd = new SparseArray<>();
-
-        synchronized (mMutex) {
-            // Rebind to non-system services if user switched
-            for (ManagedServiceInfo service : mServices) {
-                if (!service.isSystem && !service.isGuest(this)) {
-                    removableBoundServices.add(service);
-                }
-            }
-
-            mEnabledServicesForCurrentProfiles.clear();
-            mEnabledServicesPackageNames.clear();
-
-            for (int i = 0; i < nUserIds; ++i) {
-                // decode the list of components
-                final ArraySet<ComponentName> userComponents = componentsByUser.get(userIds[i]);
-                if (null == userComponents) {
-                    toAdd.put(userIds[i], new ArraySet<>());
-                    continue;
-                }
-
-                final Set<ComponentName> add = new HashSet<>(userComponents);
-                add.removeAll(mSnoozingForCurrentProfiles);
-
-                toAdd.put(userIds[i], add);
-
-                mEnabledServicesForCurrentProfiles.addAll(userComponents);
-
-                for (int j = 0; j < userComponents.size(); j++) {
-                    final ComponentName component = userComponents.valueAt(j);
-                    mEnabledServicesPackageNames.add(component.getPackageName());
-                }
-            }
-        }
-
-        for (ManagedServiceInfo info : removableBoundServices) {
-            final ComponentName component = info.component;
-            final int oldUser = info.userid;
-            final Set<ComponentName> allowedComponents = toAdd.get(info.userid);
-            if (allowedComponents != null) {
-                if (allowedComponents.contains(component) && !forceRebind) {
-                    // Already bound, don't need to bind again.
-                    allowedComponents.remove(component);
-                } else {
-                    // No longer allowed to be bound, or must rebind.
-                    Slog.v(TAG, "disabling " + getCaption() + " for user "
-                            + oldUser + ": " + component);
-                    unregisterService(component, oldUser);
-                }
-            }
-        }
+    @GuardedBy("mMutex")
+    protected void populateComponentsToBind(SparseArray<Set<ComponentName>> componentsToBind,
+            final IntArray activeUsers,
+            SparseArray<ArraySet<ComponentName>> approvedComponentsByUser) {
+        mEnabledServicesForCurrentProfiles.clear();
+        mEnabledServicesPackageNames.clear();
+        final int nUserIds = activeUsers.size();
 
         for (int i = 0; i < nUserIds; ++i) {
-            final Set<ComponentName> add = toAdd.get(userIds[i]);
+            // decode the list of components
+            final int userId = activeUsers.get(i);
+            final ArraySet<ComponentName> userComponents = approvedComponentsByUser.get(userId);
+            if (null == userComponents) {
+                componentsToBind.put(userId, new ArraySet<>());
+                continue;
+            }
+
+            final Set<ComponentName> add = new HashSet<>(userComponents);
+            add.removeAll(mSnoozingForCurrentProfiles);
+
+            componentsToBind.put(userId, add);
+
+            mEnabledServicesForCurrentProfiles.addAll(userComponents);
+
+            for (int j = 0; j < userComponents.size(); j++) {
+                final ComponentName component = userComponents.valueAt(j);
+                mEnabledServicesPackageNames.add(component.getPackageName());
+            }
+        }
+    }
+
+    @GuardedBy("mMutex")
+    protected Set<ManagedServiceInfo> getRemovableConnectedServices() {
+        final Set<ManagedServiceInfo> removableBoundServices = new ArraySet<>();
+        for (ManagedServiceInfo service : mServices) {
+            if (!service.isSystem && !service.isGuest(this)) {
+                removableBoundServices.add(service);
+            }
+        }
+        return removableBoundServices;
+    }
+
+    protected void populateComponentsToUnbind(
+            boolean forceRebind,
+            Set<ManagedServiceInfo> removableBoundServices,
+            SparseArray<Set<ComponentName>> allowedComponentsToBind,
+            SparseArray<Set<ComponentName>> componentsToUnbind) {
+        for (ManagedServiceInfo info : removableBoundServices) {
+            final Set<ComponentName> allowedComponents = allowedComponentsToBind.get(info.userid);
+            if (allowedComponents != null) {
+                if (forceRebind || !allowedComponents.contains(info.component)) {
+                    Set<ComponentName> toUnbind =
+                            componentsToUnbind.get(info.userid, new ArraySet<>());
+                    toUnbind.add(info.component);
+                    componentsToUnbind.put(info.userid, toUnbind);
+                }
+            }
+        }
+    }
+
+    /**
+     * Called whenever packages change, the user switches, or the secure setting
+     * is altered. (For example in response to USER_SWITCHED in our broadcast receiver)
+     */
+    protected void rebindServices(boolean forceRebind, int userToRebind) {
+        if (DEBUG) Slog.d(TAG, "rebindServices " + forceRebind + " " + userToRebind);
+        IntArray userIds = mUserProfiles.getCurrentProfileIds();
+        if (userToRebind != USER_ALL) {
+            userIds = new IntArray(1);
+            userIds.add(userToRebind);
+        }
+
+        final SparseArray<Set<ComponentName>> componentsToBind = new SparseArray<>();
+        final SparseArray<Set<ComponentName>> componentsToUnbind = new SparseArray<>();
+
+        synchronized (mMutex) {
+            final SparseArray<ArraySet<ComponentName>> approvedComponentsByUser =
+                    getAllowedComponents(userIds);
+            final Set<ManagedServiceInfo> removableBoundServices = getRemovableConnectedServices();
+
+            // Filter approvedComponentsByUser to collect all of the components that are allowed
+            // for the currently active user(s).
+            populateComponentsToBind(componentsToBind, userIds, approvedComponentsByUser);
+
+            // For every current non-system connection, disconnect services that are no longer
+            // approved, or ALL services if we are force rebinding
+            populateComponentsToUnbind(
+                    forceRebind, removableBoundServices, componentsToBind, componentsToUnbind);
+        }
+
+        unbindFromServices(componentsToUnbind);
+        bindToServices(componentsToBind);
+    }
+
+    protected void unbindFromServices(SparseArray<Set<ComponentName>> componentsToUnbind) {
+        for (int i = 0; i < componentsToUnbind.size(); i++) {
+            final int userId = componentsToUnbind.keyAt(i);
+            final Set<ComponentName> removableComponents = componentsToUnbind.get(userId);
+            for (ComponentName cn : removableComponents) {
+                // No longer allowed to be bound, or must rebind.
+                Slog.v(TAG, "disabling " + getCaption() + " for user " + userId + ": " + cn);
+                unregisterService(cn, userId);
+            }
+        }
+    }
+
+    // Attempt to bind to services, skipping those that cannot be found or lack the permission.
+    private void bindToServices(SparseArray<Set<ComponentName>> componentsToBind) {
+        for (int i = 0; i < componentsToBind.size(); i++) {
+            final int userId = componentsToBind.keyAt(i);
+            final Set<ComponentName> add = componentsToBind.get(userId);
             for (ComponentName component : add) {
                 try {
                     ServiceInfo info = mPm.getServiceInfo(component,
                             PackageManager.MATCH_DIRECT_BOOT_AWARE
-                                    | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userIds[i]);
+                                    | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
                     if (info == null) {
                         Slog.w(TAG, "Not binding " + getCaption() + " service " + component
                                 + ": service not found");
@@ -933,15 +987,13 @@
                         continue;
                     }
                     Slog.v(TAG,
-                            "enabling " + getCaption() + " for " + userIds[i] + ": " + component);
-                    registerService(component, userIds[i]);
+                            "enabling " + getCaption() + " for " + userId + ": " + component);
+                    registerService(component, userId);
                 } catch (RemoteException e) {
                     e.rethrowFromSystemServer();
                 }
             }
         }
-
-        mLastSeenProfileIds = userIds;
     }
 
     /**
@@ -1018,7 +1070,7 @@
 
                 @Override
                 public void onServiceConnected(ComponentName name, IBinder binder) {
-                    Slog.v(TAG, getCaption() + " service connected: " + name);
+                    Slog.v(TAG,  userid + " " + getCaption() + " service connected: " + name);
                     boolean added = false;
                     ManagedServiceInfo info = null;
                     synchronized (mMutex) {
@@ -1040,12 +1092,12 @@
 
                 @Override
                 public void onServiceDisconnected(ComponentName name) {
-                    Slog.v(TAG, getCaption() + " connection lost: " + name);
+                    Slog.v(TAG, userid + " " + getCaption() + " connection lost: " + name);
                 }
 
                 @Override
                 public void onBindingDied(ComponentName name) {
-                    Slog.w(TAG, getCaption() + " binding died: " + name);
+                    Slog.w(TAG,  userid + " " + getCaption() + " binding died: " + name);
                     synchronized (mMutex) {
                         unbindService(this, name, userid);
                         if (!mServicesRebinding.contains(servicesBindingTag)) {
@@ -1057,18 +1109,19 @@
                                     }
                                }, ON_BINDING_DIED_REBIND_DELAY_MS);
                         } else {
-                            Slog.v(TAG, getCaption() + " not rebinding as "
-                                    + "a previous rebind attempt was made: " + name);
+                            Slog.v(TAG, getCaption() + " not rebinding in user " + userid
+                                    + " as a previous rebind attempt was made: " + name);
                         }
                     }
                 }
             };
             if (!mContext.bindServiceAsUser(intent,
-                serviceConnection,
-                BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE | BIND_ALLOW_WHITELIST_MANAGEMENT,
-                new UserHandle(userid))) {
+                    serviceConnection,
+                    getBindFlags(),
+                    new UserHandle(userid))) {
                 mServicesBound.remove(servicesBindingTag);
-                Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent);
+                Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent
+                        + " in user " + userid);
                 return;
             }
         } catch (SecurityException ex) {
@@ -1232,9 +1285,9 @@
             if (!isEnabledForCurrentProfiles()) {
                 return false;
             }
-            if (this.userid == UserHandle.USER_ALL) return true;
+            if (this.userid == USER_ALL) return true;
             if (this.isSystem) return true;
-            if (nid == UserHandle.USER_ALL || nid == this.userid) return true;
+            if (nid == USER_ALL || nid == this.userid) return true;
             return supportsProfiles()
                     && mUserProfiles.isCurrentProfile(nid)
                     && isPermittedForProfile(nid);
@@ -1280,6 +1333,24 @@
                 Binder.restoreCallingIdentity(identity);
             }
         }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            ManagedServiceInfo that = (ManagedServiceInfo) o;
+            return userid == that.userid
+                    && isSystem == that.isSystem
+                    && targetSdkVersion == that.targetSdkVersion
+                    && Objects.equals(service, that.service)
+                    && Objects.equals(component, that.component)
+                    && Objects.equals(connection, that.connection);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(service, component, userid, isSystem, connection, targetSdkVersion);
+        }
     }
 
     /** convenience method for looking in mEnabledServicesForCurrentProfiles */
@@ -1305,12 +1376,15 @@
             }
         }
 
-        public int[] getCurrentProfileIds() {
+        /**
+         * Returns the currently active users (generally one user and its work profile).
+         */
+        public IntArray getCurrentProfileIds() {
             synchronized (mCurrentProfiles) {
-                int[] users = new int[mCurrentProfiles.size()];
+                IntArray users = new IntArray(mCurrentProfiles.size());
                 final int N = mCurrentProfiles.size();
                 for (int i = 0; i < N; ++i) {
-                    users[i] = mCurrentProfiles.keyAt(i);
+                    users.add(mCurrentProfiles.keyAt(i));
                 }
                 return users;
             }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 03b7652..cade07c 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -33,6 +33,10 @@
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
+import static android.content.Context.BIND_ADJUST_BELOW_PERCEPTIBLE;
+import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT;
+import static android.content.Context.BIND_AUTO_CREATE;
+import static android.content.Context.BIND_FOREGROUND_SERVICE;
 import static android.content.pm.PackageManager.FEATURE_LEANBACK;
 import static android.content.pm.PackageManager.FEATURE_TELEVISION;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
@@ -174,6 +178,7 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
+import android.util.IntArray;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -345,7 +350,7 @@
     private String mSoundNotificationKey;
     private String mVibrateNotificationKey;
 
-    private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
+    private final SparseArray<ArraySet<ComponentName>> mListenersDisablingEffects =
             new SparseArray<>();
     private List<ComponentName> mEffectsSuppressors = new ArrayList<>();
     private int mListenerHints;  // right now, all hints are global
@@ -1147,15 +1152,18 @@
                 // turn off LED when user passes through lock screen
                 mNotificationLight.turnOff();
             } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
-                final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
-                // reload per-user settings
-                mSettingsObserver.update(null);
+                final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
                 mUserProfiles.updateCache(context);
-                // Refresh managed services
-                mConditionProviders.onUserSwitched(user);
-                mListeners.onUserSwitched(user);
-                mAssistants.onUserSwitched(user);
-                mZenModeHelper.onUserSwitched(user);
+                if (!mUserProfiles.isManagedProfile(userId)) {
+                    // reload per-user settings
+                    mSettingsObserver.update(null);
+                    // Refresh managed services
+                    mConditionProviders.onUserSwitched(userId);
+                    mListeners.onUserSwitched(userId);
+                    mZenModeHelper.onUserSwitched(userId);
+                }
+                // assistant is the only thing that cares about managed profiles specifically
+                mAssistants.onUserSwitched(userId);
             } else if (action.equals(Intent.ACTION_USER_ADDED)) {
                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
                 if (userId != USER_NULL) {
@@ -1165,20 +1173,23 @@
                     }
                 }
             } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
-                final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
+                final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
                 mUserProfiles.updateCache(context);
-                mZenModeHelper.onUserRemoved(user);
-                mPreferencesHelper.onUserRemoved(user);
-                mListeners.onUserRemoved(user);
-                mConditionProviders.onUserRemoved(user);
-                mAssistants.onUserRemoved(user);
+                mZenModeHelper.onUserRemoved(userId);
+                mPreferencesHelper.onUserRemoved(userId);
+                mListeners.onUserRemoved(userId);
+                mConditionProviders.onUserRemoved(userId);
+                mAssistants.onUserRemoved(userId);
                 savePolicyFile();
             } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
-                final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
-                mConditionProviders.onUserUnlocked(user);
-                mListeners.onUserUnlocked(user);
-                mAssistants.onUserUnlocked(user);
-                mZenModeHelper.onUserUnlocked(user);
+                final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
+                mUserProfiles.updateCache(context);
+                mAssistants.onUserUnlocked(userId);
+                if (!mUserProfiles.isManagedProfile(userId)) {
+                    mConditionProviders.onUserUnlocked(userId);
+                    mListeners.onUserUnlocked(userId);
+                    mZenModeHelper.onUserUnlocked(userId);
+                }
             }
         }
     };
@@ -1562,7 +1573,7 @@
         filter.addAction(Intent.ACTION_USER_REMOVED);
         filter.addAction(Intent.ACTION_USER_UNLOCKED);
         filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
-        getContext().registerReceiver(mIntentReceiver, filter);
+        getContext().registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter, null, null);
 
         IntentFilter pkgFilter = new IntentFilter();
         pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
@@ -1694,10 +1705,10 @@
                     UserHandle.getUserId(uid), REASON_CHANNEL_BANNED,
                     null);
             if (isUidSystemOrPhone(uid)) {
-                int[] profileIds = mUserProfiles.getCurrentProfileIds();
-                int N = profileIds.length;
+                IntArray profileIds = mUserProfiles.getCurrentProfileIds();
+                int N = profileIds.size();
                 for (int i = 0; i < N; i++) {
-                    int profileId = profileIds[i];
+                    int profileId = profileIds.get(i);
                     cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
                             profileId, REASON_CHANNEL_BANNED,
                             null);
@@ -1784,10 +1795,10 @@
     private ArrayList<ComponentName> getSuppressors() {
         ArrayList<ComponentName> names = new ArrayList<ComponentName>();
         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
-            ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
+            ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i);
 
-            for (ManagedServiceInfo info : serviceInfoList) {
-                names.add(info.component);
+            for (ComponentName info : serviceInfoList) {
+                names.add(info);
             }
         }
 
@@ -1803,11 +1814,10 @@
 
         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
             final int hint = mListenersDisablingEffects.keyAt(i);
-            final ArraySet<ManagedServiceInfo> listeners =
-                    mListenersDisablingEffects.valueAt(i);
+            final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i);
 
             if (hints == 0 || (hint & hints) == hint) {
-                removed = removed || listeners.remove(info);
+                removed |= listeners.remove(info.component);
             }
         }
 
@@ -1830,18 +1840,18 @@
 
     private void addDisabledHint(ManagedServiceInfo info, int hint) {
         if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
-            mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
+            mListenersDisablingEffects.put(hint, new ArraySet<>());
         }
 
-        ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
-        hintListeners.add(info);
+        ArraySet<ComponentName> hintListeners = mListenersDisablingEffects.get(hint);
+        hintListeners.add(info.component);
     }
 
     private int calculateHints() {
         int hints = 0;
         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
             int hint = mListenersDisablingEffects.keyAt(i);
-            ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
+            ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i);
 
             if (!serviceInfoList.isEmpty()) {
                 hints |= hint;
@@ -2387,7 +2397,7 @@
                 String pkg) {
             checkCallerIsSystemOrSameApp(pkg);
             return mPreferencesHelper.getNotificationChannelGroups(
-                    pkg, Binder.getCallingUid(), false, false);
+                    pkg, Binder.getCallingUid(), false, false, true);
         }
 
         @Override
@@ -2463,7 +2473,8 @@
         public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
                 String pkg, int uid, boolean includeDeleted) {
             checkCallerIsSystem();
-            return mPreferencesHelper.getNotificationChannelGroups(pkg, uid, includeDeleted, true);
+            return mPreferencesHelper.getNotificationChannelGroups(
+                    pkg, uid, includeDeleted, true, false);
         }
 
         @Override
@@ -2955,6 +2966,21 @@
         }
 
         @Override
+        public void clearRequestedListenerHints(INotificationListener token) {
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mNotificationLock) {
+                    final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
+                    removeDisabledHints(info);
+                    updateListenerHintsLocked();
+                    updateEffectsSuppressorLocked();
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         public void requestHintsFromListener(INotificationListener token, int hints) {
             final long identity = Binder.clearCallingIdentity();
             try {
@@ -3860,11 +3886,12 @@
 
                 proto.write(
                     ListenersDisablingEffectsProto.HINT, mListenersDisablingEffects.keyAt(i));
-                final ArraySet<ManagedServiceInfo> listeners =
+                final ArraySet<ComponentName> listeners =
                     mListenersDisablingEffects.valueAt(i);
                 for (int j = 0; j < listeners.size(); j++) {
-                    final ManagedServiceInfo listener = listeners.valueAt(i);
-                    listener.writeToProto(proto, ListenersDisablingEffectsProto.LISTENERS, null);
+                    final ComponentName componentName = listeners.valueAt(i);
+                    componentName.writeToProto(proto,
+                            ListenersDisablingEffectsProto.LISTENER_COMPONENTS);
                 }
 
                 proto.end(effectsToken);
@@ -4003,15 +4030,14 @@
                     if (i > 0) pw.print(';');
                     pw.print("hint[" + hint + "]:");
 
-                    final ArraySet<ManagedServiceInfo> listeners =
-                            mListenersDisablingEffects.valueAt(i);
+                    final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i);
                     final int listenerSize = listeners.size();
 
                     for (int j = 0; j < listenerSize; j++) {
                         if (i > 0) pw.print(',');
-                        final ManagedServiceInfo listener = listeners.valueAt(i);
+                        final ComponentName listener = listeners.valueAt(i);
                         if (listener != null) {
-                            pw.print(listener.component);
+                            pw.print(listener);
                         }
                     }
                 }
@@ -4070,25 +4096,30 @@
         public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
                 int userId) {
             checkCallerIsSystem();
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    synchronized (mNotificationLock) {
-                        removeForegroundServiceFlagByListLocked(
-                                mEnqueuedNotifications, pkg, notificationId, userId);
-                        removeForegroundServiceFlagByListLocked(
-                                mNotificationList, pkg, notificationId, userId);
+            mHandler.post(() -> {
+                synchronized (mNotificationLock) {
+                    // strip flag from all enqueued notifications. listeners will be informed
+                    // in post runnable.
+                    List<NotificationRecord> enqueued = findNotificationsByListLocked(
+                            mEnqueuedNotifications, pkg, null, notificationId, userId);
+                    for (int i = 0; i < enqueued.size(); i++) {
+                        removeForegroundServiceFlagLocked(enqueued.get(i));
+                    }
+
+                    // if posted notification exists, strip its flag and tell listeners
+                    NotificationRecord r = findNotificationByListLocked(
+                            mNotificationList, pkg, null, notificationId, userId);
+                    if (r != null) {
+                        removeForegroundServiceFlagLocked(r);
+                        mRankingHelper.sort(mNotificationList);
+                        mListeners.notifyPostedLocked(r, r);
                     }
                 }
             });
         }
 
         @GuardedBy("mNotificationLock")
-        private void removeForegroundServiceFlagByListLocked(
-                ArrayList<NotificationRecord> notificationList, String pkg, int notificationId,
-                int userId) {
-            NotificationRecord r = findNotificationByListLocked(
-                    notificationList, pkg, null, notificationId, userId);
+        private void removeForegroundServiceFlagLocked(NotificationRecord r) {
             if (r == null) {
                 return;
             }
@@ -4099,8 +4130,6 @@
             // initially *and* force remove FLAG_FOREGROUND_SERVICE.
             sbn.getNotification().flags =
                     (r.mOriginalFlags & ~FLAG_FOREGROUND_SERVICE);
-            mRankingHelper.sort(mNotificationList);
-            mListeners.notifyPostedLocked(r, r);
         }
     };
 
@@ -4255,8 +4284,12 @@
     @VisibleForTesting
     int resolveNotificationUid(String callingPkg, String targetPkg,
             int callingUid, int userId) {
+        if (userId == UserHandle.USER_ALL) {
+            userId = USER_SYSTEM;
+        }
         // posted from app A on behalf of app A
-        if (isCallerSameApp(targetPkg, callingUid) && TextUtils.equals(callingPkg, targetPkg)) {
+        if (isCallerSameApp(targetPkg, callingUid, userId)
+                && TextUtils.equals(callingPkg, targetPkg)) {
             return callingUid;
         }
 
@@ -4293,7 +4326,7 @@
         if (!isSystemNotification && !isNotificationFromListener) {
             synchronized (mNotificationLock) {
                 if (mNotificationsByKey.get(r.sbn.getKey()) == null
-                        && isCallerInstantApp(pkg, callingUid)) {
+                        && isCallerInstantApp(pkg, callingUid, r.getUserId())) {
                     // Ephemeral apps have some special constraints for notifications.
                     // They are not allowed to create new notifications however they are allowed to
                     // update notifications created by the system (e.g. a foreground service
@@ -4381,22 +4414,12 @@
     }
 
     protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
-        final String pkg = r.sbn.getPackageName();
-        final int callingUid = r.sbn.getUid();
-
-        final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
-        if (isPackageSuspended) {
-            Slog.e(TAG, "Suppressing notification from package due to package "
-                    + "suspended by administrator.");
-            usageStats.registerSuspendedByAdmin(r);
-            return isPackageSuspended;
-        }
-        final boolean isBlocked = isBlocked(r);
-        if (isBlocked) {
+        if (isBlocked(r)) {
             Slog.e(TAG, "Suppressing notification from package by user request.");
             usageStats.registerBlocked(r);
+            return true;
         }
-        return isBlocked;
+        return false;
     }
 
     private boolean isBlocked(NotificationRecord r) {
@@ -4670,7 +4693,11 @@
                         return;
                     }
 
-                    r.setHidden(isPackageSuspendedLocked(r));
+                    final boolean isPackageSuspended = isPackageSuspendedLocked(r);
+                    r.setHidden(isPackageSuspended);
+                    if (isPackageSuspended) {
+                        mUsageStats.registerSuspendedByAdmin(r);
+                    }
                     NotificationRecord old = mNotificationsByKey.get(key);
                     final StatusBarNotification n = r.sbn;
                     final Notification notification = n.getNotification();
@@ -6253,6 +6280,21 @@
     }
 
     @GuardedBy("mNotificationLock")
+    private List<NotificationRecord> findNotificationsByListLocked(
+            ArrayList<NotificationRecord> list, String pkg, String tag, int id, int userId) {
+        List<NotificationRecord> matching = new ArrayList<>();
+        final int len = list.size();
+        for (int i = 0; i < len; i++) {
+            NotificationRecord r = list.get(i);
+            if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
+                    TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
+                matching.add(r);
+            }
+        }
+        return matching;
+    }
+
+    @GuardedBy("mNotificationLock")
     private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
             String key) {
         final int N = list.size();
@@ -6378,7 +6420,8 @@
         }
     }
 
-    private boolean isCallerInstantApp(String pkg, int callingUid) {
+    @VisibleForTesting
+    boolean isCallerInstantApp(String pkg, int callingUid, int userId) {
         // System is always allowed to act for ephemeral apps.
         if (isUidSystemOrPhone(callingUid)) {
             return false;
@@ -6387,8 +6430,7 @@
         mAppOps.checkPackage(callingUid, pkg);
 
         try {
-            ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
-                    UserHandle.getCallingUserId());
+            ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0, userId);
             if (ai == null) {
                 throw new SecurityException("Unknown package " + pkg);
             }
@@ -6400,13 +6442,13 @@
     }
 
     private void checkCallerIsSameApp(String pkg) {
-        checkCallerIsSameApp(pkg, Binder.getCallingUid());
+        checkCallerIsSameApp(pkg, Binder.getCallingUid(), UserHandle.getCallingUserId());
     }
 
-    private void checkCallerIsSameApp(String pkg, int uid) {
+    private void checkCallerIsSameApp(String pkg, int uid, int userId) {
         try {
             ApplicationInfo ai = mPackageManager.getApplicationInfo(
-                    pkg, 0, UserHandle.getCallingUserId());
+                    pkg, 0, userId);
             if (ai == null) {
                 throw new SecurityException("Unknown package " + pkg);
             }
@@ -6428,9 +6470,9 @@
         }
     }
 
-    private boolean isCallerSameApp(String pkg, int uid) {
+    private boolean isCallerSameApp(String pkg, int uid, int userId) {
         try {
-            checkCallerIsSameApp(pkg, uid);
+            checkCallerIsSameApp(pkg, uid, userId);
             return true;
         } catch (SecurityException e) {
             return false;
@@ -6661,7 +6703,9 @@
         @Override
         public void onUserUnlocked(int user) {
             if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
-            rebindServices(true);
+            // force rebind the assistant, as it might be keeping its own state in user locked
+            // storage
+            rebindServices(true, user);
         }
 
         protected void onNotificationsSeenLocked(ArrayList<NotificationRecord> records) {
@@ -6786,6 +6830,16 @@
         }
 
         @Override
+        protected int getBindFlags() {
+            // Most of the same flags as the base, but also add BIND_ADJUST_BELOW_PERCEPTIBLE
+            // because too many 3P apps could be kept in memory as notification listeners and
+            // cause extreme memory pressure.
+            // TODO: Change the binding lifecycle of NotificationListeners to avoid this situation.
+            return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE
+                    | BIND_ADJUST_BELOW_PERCEPTIBLE | BIND_ALLOW_WHITELIST_MANAGEMENT;
+        }
+
+        @Override
         protected Config getConfig() {
             Config c = new Config();
             c.caption = "notification listener";
@@ -6876,7 +6930,6 @@
                 if (!oldSbnVisible && !sbnVisible) {
                     continue;
                 }
-
                 // If the notification is hidden, don't notifyPosted listeners targeting < P.
                 // Instead, those listeners will receive notifyPosted when the notification is
                 // unhidden.
@@ -7310,7 +7363,7 @@
                 new String[]{pkg});
 
         final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED
-            : Intent.ACTION_PACKAGES_UNSUSPENDED;
+                : Intent.ACTION_PACKAGES_UNSUSPENDED;
         final Intent intent = new Intent(action);
         intent.putExtras(extras);
 
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 13ff6e8..3a0ab77 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -755,7 +755,7 @@
 
     @Override
     public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
-            int uid, boolean includeDeleted, boolean includeNonGrouped) {
+            int uid, boolean includeDeleted, boolean includeNonGrouped, boolean includeEmpty) {
         Preconditions.checkNotNull(pkg);
         Map<String, NotificationChannelGroup> groups = new ArrayMap<>();
         PackagePreferences r = getPackagePreferences(pkg, uid);
@@ -786,6 +786,13 @@
         if (includeNonGrouped && nonGrouped.getChannels().size() > 0) {
             groups.put(null, nonGrouped);
         }
+        if (includeEmpty) {
+            for (NotificationChannelGroup group : r.groups.values()) {
+                if (!groups.containsKey(group.getId())) {
+                    groups.put(group.getId(), group);
+                }
+            }
+        }
         return new ParceledListSlice<>(new ArrayList<>(groups.values()));
     }
 
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index af64683..605348b 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -36,7 +36,7 @@
     void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
             boolean fromTargetApp);
     ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
-            int uid, boolean includeDeleted, boolean includeNonGrouped);
+            int uid, boolean includeDeleted, boolean includeNonGrouped, boolean includeEmpty);
     void createNotificationChannel(String pkg, int uid, NotificationChannel channel,
             boolean fromTargetApp, boolean hasDndAccess);
     void updateNotificationChannel(String pkg, int uid, NotificationChannel channel, boolean fromUser);
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index a178a52..2b581d6 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -15,17 +15,8 @@
  */
 package com.android.server.notification;
 
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
 import android.annotation.NonNull;
 import android.app.AlarmManager;
-import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -37,9 +28,18 @@
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.util.ArrayMap;
+import android.util.IntArray;
 import android.util.Log;
 import android.util.Slog;
 
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -105,12 +105,12 @@
 
     protected @NonNull List<NotificationRecord> getSnoozed() {
         List<NotificationRecord> snoozedForUser = new ArrayList<>();
-        int[] userIds = mUserProfiles.getCurrentProfileIds();
+        IntArray userIds = mUserProfiles.getCurrentProfileIds();
         if (userIds != null) {
-            final int N = userIds.length;
+            final int N = userIds.size();
             for (int i = 0; i < N; i++) {
                 final ArrayMap<String, ArrayMap<String, NotificationRecord>> snoozedPkgs =
-                        mSnoozedNotifications.get(userIds[i]);
+                        mSnoozedNotifications.get(userIds.get(i));
                 if (snoozedPkgs != null) {
                     final int M = snoozedPkgs.size();
                     for (int j = 0; j < M; j++) {
@@ -179,7 +179,7 @@
     protected boolean cancel(int userId, boolean includeCurrentProfiles) {
         int[] userIds = {userId};
         if (includeCurrentProfiles) {
-            userIds = mUserProfiles.getCurrentProfileIds();
+            userIds = mUserProfiles.getCurrentProfileIds().toArray();
         }
         final int N = userIds.length;
         for (int i = 0; i < N; i++) {
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 6ac72d3..760f155 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -52,8 +52,6 @@
 import android.service.notification.Condition;
 import android.service.notification.ConditionProviderService;
 import android.service.notification.ZenModeConfig;
-import android.service.notification.ZenModeConfig.EventInfo;
-import android.service.notification.ZenModeConfig.ScheduleInfo;
 import android.service.notification.ZenModeConfig.ZenRule;
 import android.service.notification.ZenModeProto;
 import android.util.AndroidRuntimeException;
@@ -119,8 +117,6 @@
     public static final long SUPPRESSED_EFFECT_ALL = SUPPRESSED_EFFECT_CALLS
             | SUPPRESSED_EFFECT_NOTIFICATIONS;
 
-    protected String mDefaultRuleEveryNightName;
-    protected String mDefaultRuleEventsName;
     @VisibleForTesting protected boolean mIsBootComplete;
 
     public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders) {
@@ -130,9 +126,9 @@
         mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
         mNotificationManager =  context.getSystemService(NotificationManager.class);
 
-        mDefaultConfig = new ZenModeConfig();
-        setDefaultZenRules(mContext);
-        mConfig = mDefaultConfig;
+        mDefaultConfig = readDefaultConfig(mContext.getResources());
+        updateDefaultAutomaticRuleNames();
+        mConfig = mDefaultConfig.copy();
         mConfigs.put(UserHandle.USER_SYSTEM, mConfig);
 
         mSettingsObserver = new SettingsObserver(mHandler);
@@ -311,7 +307,9 @@
             newConfig = mConfig.copy();
             ZenRule rule = new ZenRule();
             populateZenRule(automaticZenRule, rule, true);
-            newConfig.automaticRules.put(rule.id, rule);
+            if (newConfig.automaticRules.put(rule.id, rule) != null) {
+                rule.modified = true;
+            }
             if (setConfigLocked(newConfig, reason, rule.component, true)) {
                 return rule.id;
             } else {
@@ -341,7 +339,9 @@
                 }
             }
             populateZenRule(automaticZenRule, rule, false);
-            newConfig.automaticRules.put(ruleId, rule);
+            if (newConfig.automaticRules.put(ruleId, rule) != null) {
+                rule.modified = true;
+            }
             return setConfigLocked(newConfig, reason, rule.component, true);
         }
     }
@@ -413,17 +413,6 @@
         }
     }
 
-    public void setDefaultZenRules(Context context) {
-        mDefaultConfig = readDefaultConfig(context.getResources());
-        appendDefaultRules(mDefaultConfig);
-    }
-
-    private void appendDefaultRules (ZenModeConfig config) {
-        getDefaultRuleNames();
-        appendDefaultEveryNightRule(config);
-        appendDefaultEventRules(config);
-    }
-
     // Checks zen rule properties are the same (doesn't check creation time, name nor enabled)
     // used to check if default rules were customized or not
     private boolean ruleValuesEqual(AutomaticZenRule rule, ZenRule defaultRule) {
@@ -437,22 +426,16 @@
     }
 
     protected void updateDefaultZenRules() {
-        ZenModeConfig configDefaultRules = new ZenModeConfig();
-        appendDefaultRules(configDefaultRules); // "new" localized default rules
-        for (String ruleId : ZenModeConfig.DEFAULT_RULE_IDS) {
-            AutomaticZenRule currRule = getAutomaticZenRule(ruleId);
-            ZenRule defaultRule = configDefaultRules.automaticRules.get(ruleId);
-            // if default rule wasn't customized, use localized name instead of previous
-            if (ruleValuesEqual(currRule, defaultRule) &&
-                    !defaultRule.name.equals(currRule.getName())) {
+        updateDefaultAutomaticRuleNames();
+        for (ZenRule defaultRule : mDefaultConfig.automaticRules.values()) {
+            ZenRule currRule = mConfig.automaticRules.get(defaultRule.id);
+            // if default rule wasn't modified, use localized name instead of previous
+            if (currRule != null && !currRule.modified && !defaultRule.name.equals(currRule.name)) {
                 if (canManageAutomaticZenRule(defaultRule)) {
                     if (DEBUG) Slog.d(TAG, "Locale change - updating default zen rule name "
-                            + "from " + currRule.getName() + " to " + defaultRule.name);
+                            + "from " + currRule.name + " to " + defaultRule.name);
                     // update default rule (if locale changed, name of rule will change)
-                    AutomaticZenRule defaultAutoRule = createAutomaticZenRule(defaultRule);
-                    // ensure enabled state is carried over from current rule
-                    defaultAutoRule.setEnabled(currRule.isEnabled());
-                    updateAutomaticZenRule(ruleId, defaultAutoRule,
+                    updateAutomaticZenRule(defaultRule.id, createAutomaticZenRule(defaultRule),
                             "locale changed");
                 }
             }
@@ -501,9 +484,14 @@
     }
 
     protected AutomaticZenRule createAutomaticZenRule(ZenRule rule) {
-        return new AutomaticZenRule(rule.name, rule.component, rule.conditionId,
-                NotificationManager.zenModeToInterruptionFilter(rule.zenMode), rule.enabled,
-                rule.creationTime);
+        if (rule.zenPolicy != null) {
+            return new AutomaticZenRule(rule.name, rule.component, rule.conditionId, rule.zenPolicy,
+                    rule.enabled, rule.creationTime);
+        } else {
+            return new AutomaticZenRule(rule.name, rule.component, rule.conditionId,
+                    NotificationManager.zenModeToInterruptionFilter(rule.zenMode), rule.enabled,
+                    rule.creationTime);
+        }
     }
 
     public void setManualZenMode(int zenMode, Uri conditionId, String caller, String reason) {
@@ -637,7 +625,9 @@
                 // - doesn't already have default rules and
                 // - all previous automatic rules were disabled
                 config.automaticRules = new ArrayMap<>();
-                appendDefaultRules(config);
+                for (ZenRule rule : mDefaultConfig.automaticRules.values()) {
+                    config.automaticRules.put(rule.id, rule);
+                }
                 reason += ", reset to default rules";
             }
 
@@ -667,6 +657,9 @@
         }
     }
 
+    /**
+     * @return user-specified default notification policy for priority only do not disturb
+     */
     public Policy getNotificationPolicy() {
         return getNotificationPolicy(mConfig);
     }
@@ -675,6 +668,9 @@
         return config == null ? null : config.toNotificationPolicy();
     }
 
+    /**
+     * Sets the global notification policy used for priority only do not disturb
+     */
     public void setNotificationPolicy(Policy policy) {
         if (policy == null || mConfig == null) return;
         synchronized (mConfig) {
@@ -770,9 +766,7 @@
             ComponentName triggeringComponent, boolean setRingerMode) {
         final String val = Integer.toString(config.hashCode());
         Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
-        if (!evaluateZenMode(reason, setRingerMode)) {
-            applyRestrictions();  // evaluateZenMode will also apply restrictions if changed
-        }
+        evaluateZenMode(reason, setRingerMode);
         mConditions.evaluateConfig(config, triggeringComponent, true /*processSubscriptions*/);
     }
 
@@ -798,7 +792,7 @@
     }
 
     @VisibleForTesting
-    protected boolean evaluateZenMode(String reason, boolean setRingerMode) {
+    protected void evaluateZenMode(String reason, boolean setRingerMode) {
         if (DEBUG) Log.d(TAG, "evaluateZenMode");
         final int zenBefore = mZenMode;
         final int zen = computeZenMode();
@@ -813,7 +807,6 @@
         if (zen != zenBefore) {
             mHandler.postDispatchOnZenModeChanged();
         }
-        return true;
     }
 
     private void updateRingerModeAffectedStreams() {
@@ -822,7 +815,9 @@
         }
     }
 
+
     private int computeZenMode() {
+        // TODO: use mConfig.zenPolicy
         if (mConfig == null) return Global.ZEN_MODE_OFF;
         synchronized (mConfig) {
             if (mConfig.manualRule != null) return mConfig.manualRule.zenMode;
@@ -844,12 +839,16 @@
         }
     }
 
-    private void getDefaultRuleNames() {
-        // on locale-change, these values differ
-        mDefaultRuleEveryNightName = mContext.getResources()
-                .getString(R.string.zen_mode_default_every_night_name);
-        mDefaultRuleEventsName = mContext.getResources()
-                .getString(R.string.zen_mode_default_events_name);
+    private void updateDefaultAutomaticRuleNames() {
+        for (ZenRule rule : mDefaultConfig.automaticRules.values()) {
+            if (ZenModeConfig.EVENTS_DEFAULT_RULE_ID.equals(rule.id)) {
+                rule.name = mContext.getResources()
+                        .getString(R.string.zen_mode_default_events_name);
+            } else if (ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID.equals(rule.id)) {
+                rule.name = mContext.getResources()
+                        .getString(R.string.zen_mode_default_every_night_name);
+            }
+        }
     }
 
     @VisibleForTesting
@@ -991,42 +990,6 @@
         return new ZenModeConfig();
     }
 
-    private void appendDefaultEveryNightRule(ZenModeConfig config) {
-        if (config == null) return;
-
-        final ScheduleInfo weeknights = new ScheduleInfo();
-        weeknights.days = ZenModeConfig.ALL_DAYS;
-        weeknights.startHour = 22;
-        weeknights.endHour = 7;
-        weeknights.exitAtAlarm = true;
-        final ZenRule rule = new ZenRule();
-        rule.enabled = false;
-        rule.name = mDefaultRuleEveryNightName;
-        rule.conditionId = ZenModeConfig.toScheduleConditionId(weeknights);
-        rule.zenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
-        rule.component = ScheduleConditionProvider.COMPONENT;
-        rule.id = ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID;
-        rule.creationTime = System.currentTimeMillis();
-        config.automaticRules.put(rule.id, rule);
-    }
-
-    private void appendDefaultEventRules(ZenModeConfig config) {
-        if (config == null) return;
-
-        final EventInfo events = new EventInfo();
-        events.calendar = null; // any calendar
-        events.reply = EventInfo.REPLY_YES_OR_MAYBE;
-        final ZenRule rule = new ZenRule();
-        rule.enabled = false;
-        rule.name = mDefaultRuleEventsName;
-        rule.conditionId = ZenModeConfig.toEventConditionId(events);
-        rule.zenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
-        rule.component = EventConditionProvider.COMPONENT;
-        rule.id = ZenModeConfig.EVENTS_DEFAULT_RULE_ID;
-        rule.creationTime = System.currentTimeMillis();
-        config.automaticRules.put(rule.id, rule);
-    }
-
     private static int zenSeverity(int zen) {
         switch (zen) {
             case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: return 1;
@@ -1198,13 +1161,13 @@
         final boolean showNotification = mIsBootComplete
                 && zen != Global.ZEN_MODE_OFF
                 && !isWatch
-                && Settings.Global.getInt(mContext.getContentResolver(),
+                && Settings.Secure.getInt(mContext.getContentResolver(),
                 Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 0) != 0
-                && Settings.Global.getInt(mContext.getContentResolver(),
+                && Settings.Secure.getInt(mContext.getContentResolver(),
                 Settings.Secure.ZEN_SETTINGS_UPDATED, 0) != 1;
 
         if (isWatch) {
-            Settings.Global.putInt(mContext.getContentResolver(),
+            Settings.Secure.putInt(mContext.getContentResolver(),
                     Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 0);
         }
 
diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java
index 7d762d9..3b11525 100644
--- a/services/core/java/com/android/server/pm/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/ComponentResolver.java
@@ -378,7 +378,7 @@
         for (int i = newIntents.size() - 1; i >= 0; --i) {
             final PackageParser.ActivityIntentInfo intentInfo = newIntents.get(i);
             final PackageParser.Package disabledPkg = sPackageManagerInternal
-                    .getDisabledPackage(intentInfo.activity.info.packageName);
+                    .getDisabledSystemPackage(intentInfo.activity.info.packageName);
             final List<PackageParser.Activity> systemActivities =
                     disabledPkg != null ? disabledPkg.activities : null;
             adjustPriority(systemActivities, intentInfo, setupWizardPackage);
@@ -1048,11 +1048,14 @@
                         final String otherPackageName =
                                 (other != null && other.getComponentName() != null)
                                         ? other.getComponentName().getPackageName() : "?";
-                        throw new PackageManagerException(
-                                INSTALL_FAILED_CONFLICTING_PROVIDER,
-                                "Can't install because provider name " + names[j]
-                                        + " (in package " + pkg.applicationInfo.packageName
-                                        + ") is already used by " + otherPackageName);
+                        // if we're installing over the same already-installed package, this is ok
+                        if (!otherPackageName.equals(pkg.packageName)) {
+                            throw new PackageManagerException(
+                                    INSTALL_FAILED_CONFLICTING_PROVIDER,
+                                    "Can't install because provider name " + names[j]
+                                            + " (in package " + pkg.applicationInfo.packageName
+                                            + ") is already used by " + otherPackageName);
+                        }
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index bca3ca7..5810e30 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -53,16 +53,13 @@
     private final static String TAG = "OTADexopt";
     private final static boolean DEBUG_DEXOPT = true;
 
-    // The synthetic library dependencies denoting "no checks."
-    private final static String[] NO_LIBRARIES =
-            new String[] { PackageDexOptimizer.SKIP_SHARED_LIBRARY_CHECK };
-
     // The amount of "available" (free - low threshold) space necessary at the start of an OTA to
     // not bulk-delete unused apps' odex files.
     private final static long BULK_DELETE_THRESHOLD = 1024 * 1024 * 1024;  // 1GB.
 
     private final Context mContext;
     private final PackageManagerService mPackageManagerService;
+    private final MetricsLogger metricsLogger;
 
     // TODO: Evaluate the need for WeakReferences here.
 
@@ -95,6 +92,7 @@
     public OtaDexoptService(Context context, PackageManagerService packageManagerService) {
         this.mContext = context;
         this.mPackageManagerService = packageManagerService;
+        metricsLogger = new MetricsLogger();
     }
 
     public static OtaDexoptService main(Context context,
@@ -286,8 +284,8 @@
                     throws InstallerException {
                 final StringBuilder builder = new StringBuilder();
 
-                // The current version.
-                builder.append("9 ");
+                // The current version. For v10, see b/115993344.
+                builder.append("10 ");
 
                 builder.append("dexopt");
 
@@ -336,11 +334,6 @@
                 collectingInstaller, mPackageManagerService.mInstallLock, mContext);
 
         String[] libraryDependencies = pkg.usesLibraryFiles;
-        if (pkg.isSystem()) {
-            // For system apps, we want to avoid classpaths checks.
-            libraryDependencies = NO_LIBRARIES;
-        }
-
 
         optimizer.performDexOpt(pkg, libraryDependencies,
                 null /* ISAs */,
@@ -445,24 +438,22 @@
     private void performMetricsLogging() {
         long finalTime = System.nanoTime();
 
-        MetricsLogger.histogram(mContext, "ota_dexopt_available_space_before_mb",
+        metricsLogger.histogram("ota_dexopt_available_space_before_mb",
                 inMegabytes(availableSpaceBefore));
-        MetricsLogger.histogram(mContext, "ota_dexopt_available_space_after_bulk_delete_mb",
+        metricsLogger.histogram("ota_dexopt_available_space_after_bulk_delete_mb",
                 inMegabytes(availableSpaceAfterBulkDelete));
-        MetricsLogger.histogram(mContext, "ota_dexopt_available_space_after_dexopt_mb",
+        metricsLogger.histogram("ota_dexopt_available_space_after_dexopt_mb",
                 inMegabytes(availableSpaceAfterDexopt));
 
-        MetricsLogger.histogram(mContext, "ota_dexopt_num_important_packages",
-                importantPackageCount);
-        MetricsLogger.histogram(mContext, "ota_dexopt_num_other_packages", otherPackageCount);
+        metricsLogger.histogram("ota_dexopt_num_important_packages", importantPackageCount);
+        metricsLogger.histogram("ota_dexopt_num_other_packages", otherPackageCount);
 
-        MetricsLogger.histogram(mContext, "ota_dexopt_num_commands", dexoptCommandCountTotal);
-        MetricsLogger.histogram(mContext, "ota_dexopt_num_commands_executed",
-                dexoptCommandCountExecuted);
+        metricsLogger.histogram("ota_dexopt_num_commands", dexoptCommandCountTotal);
+        metricsLogger.histogram("ota_dexopt_num_commands_executed", dexoptCommandCountExecuted);
 
         final int elapsedTimeSeconds =
                 (int) TimeUnit.NANOSECONDS.toSeconds(finalTime - otaDexoptTimeStart);
-        MetricsLogger.histogram(mContext, "ota_dexopt_time_s", elapsedTimeSeconds);
+        metricsLogger.histogram("ota_dexopt_time_s", elapsedTimeSeconds);
     }
 
     private static class OTADexoptPackageDexOptimizer extends
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index adf95dc..e10827b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -111,7 +111,8 @@
 import static com.android.server.pm.PackageManagerServiceUtils.verifySignatures;
 import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_FAILURE;
 import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_SUCCESS;
-import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
+import static com.android.server.pm.permission.PermissionsState
+        .PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
 
 import android.Manifest;
 import android.annotation.IntDef;
@@ -231,6 +232,7 @@
 import android.os.storage.StorageManagerInternal;
 import android.os.storage.VolumeInfo;
 import android.os.storage.VolumeRecord;
+import android.permission.PermissionManager;
 import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
 import android.security.KeyStore;
@@ -303,7 +305,8 @@
 import com.android.server.pm.dex.PackageDexUsage;
 import com.android.server.pm.permission.BasePermission;
 import com.android.server.pm.permission.DefaultPermissionGrantPolicy;
-import com.android.server.pm.permission.DefaultPermissionGrantPolicy.DefaultPermissionGrantedCallback;
+import com.android.server.pm.permission.DefaultPermissionGrantPolicy
+        .DefaultPermissionGrantedCallback;
 import com.android.server.pm.permission.PermissionManagerInternal;
 import com.android.server.pm.permission.PermissionManagerInternal.PermissionCallback;
 import com.android.server.pm.permission.PermissionManagerService;
@@ -716,6 +719,8 @@
     @GuardedBy("mPackages")
     final private ArraySet<PackageListObserver> mPackageListObservers = new ArraySet<>();
 
+    private PackageManager mPackageManager;
+
     class PackageParserCallback implements PackageParser.Callback {
         @Override public final boolean hasFeature(String feature) {
             return PackageManagerService.this.hasSystemFeature(feature, 0);
@@ -2908,13 +2913,15 @@
             if (mIsUpgrade) {
                 final int callingUid = getCallingUid();
 
-                final int numSplitPerms = PackageParser.SPLIT_PERMISSIONS.length;
+                final List<PermissionManager.SplitPermissionInfo> splitPermissions =
+                        mContext.getSystemService(PermissionManager.class).getSplitPermissions();
+                final int numSplitPerms = splitPermissions.size();
                 for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) {
-                    final PackageParser.SplitPermissionInfo splitPerm =
-                            PackageParser.SPLIT_PERMISSIONS[splitPermNum];
-                    final String rootPerm = splitPerm.rootPerm;
+                    final PermissionManager.SplitPermissionInfo splitPerm =
+                            splitPermissions.get(splitPermNum);
+                    final String rootPerm = splitPerm.getRootPermission();
 
-                    if (preUpgradeSdkVersion >= splitPerm.targetSdk) {
+                    if (preUpgradeSdkVersion >= splitPerm.getTargetSdk()) {
                         continue;
                     }
 
@@ -2922,7 +2929,7 @@
                     for (int packageNum = 0; packageNum < numPackages; packageNum++) {
                         final PackageParser.Package pkg = mPackages.valueAt(packageNum);
 
-                        if (pkg.applicationInfo.targetSdkVersion >= splitPerm.targetSdk
+                        if (pkg.applicationInfo.targetSdkVersion >= splitPerm.getTargetSdk()
                                 || !pkg.requestedPermissions.contains(rootPerm)) {
                             continue;
                         }
@@ -2934,7 +2941,7 @@
                             continue;
                         }
 
-                        final String[] newPerms = splitPerm.newPerms;
+                        final String[] newPerms = splitPerm.getNewPermissions();
 
                         final int numNewPerms = newPerms.length;
                         for (int newPermNum = 0; newPermNum < numNewPerms; newPermNum++) {
@@ -8582,7 +8589,10 @@
                             null /* originalPkgSetting */, null, parseFlags, scanFlags,
                             (pkg == mPlatformPackage), user);
                     applyPolicy(pkg, parseFlags, scanFlags, mPlatformPackage);
-                    scanPackageOnlyLI(request, mFactoryTest, -1L);
+                    final ScanResult scanResult = scanPackageOnlyLI(request, mFactoryTest, -1L);
+                    if (scanResult.existingSettingCopied && scanResult.request.pkgSetting != null) {
+                        scanResult.request.pkgSetting.updateFrom(scanResult.pkgSetting);
+                    }
                 }
             }
         }
@@ -9805,6 +9815,11 @@
         /** Whether or not the package scan was successful */
         public final boolean success;
         /**
+         * Whether or not the original PackageSetting needs to be updated with this result on
+         * commit.
+         */
+        public final boolean existingSettingCopied;
+        /**
          * The final package settings. This may be the same object passed in
          * the {@link ScanRequest}, but, with modified values.
          */
@@ -9814,11 +9829,12 @@
         public ScanResult(
                 ScanRequest request, boolean success,
                 @Nullable PackageSetting pkgSetting,
-                @Nullable List<String> changedAbiCodePath) {
+                @Nullable List<String> changedAbiCodePath, boolean existingSettingCopied) {
             this.request = request;
             this.success = success;
             this.pkgSetting = pkgSetting;
             this.changedAbiCodePath = changedAbiCodePath;
+            this.existingSettingCopied = existingSettingCopied;
         }
     }
 
@@ -9895,26 +9911,34 @@
     private @ScanFlags int adjustScanFlags(@ScanFlags int scanFlags,
             PackageSetting pkgSetting, PackageSetting disabledPkgSetting, UserHandle user,
             PackageParser.Package pkg) {
-        if (disabledPkgSetting != null) {
+
+        // TODO(patb): Do away entirely with disabledPkgSetting here. PkgSetting will always contain
+        // the correct isSystem value now that we don't disable system packages before scan.
+        final PackageSetting systemPkgSetting =
+                (scanFlags & SCAN_NEW_INSTALL) != 0 && disabledPkgSetting == null
+                        && pkgSetting != null && pkgSetting.isSystem()
+                        ? pkgSetting
+                        : disabledPkgSetting;
+        if (systemPkgSetting != null)  {
             // updated system application, must at least have SCAN_AS_SYSTEM
             scanFlags |= SCAN_AS_SYSTEM;
-            if ((disabledPkgSetting.pkgPrivateFlags
+            if ((systemPkgSetting.pkgPrivateFlags
                     & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
                 scanFlags |= SCAN_AS_PRIVILEGED;
             }
-            if ((disabledPkgSetting.pkgPrivateFlags
+            if ((systemPkgSetting.pkgPrivateFlags
                     & ApplicationInfo.PRIVATE_FLAG_OEM) != 0) {
                 scanFlags |= SCAN_AS_OEM;
             }
-            if ((disabledPkgSetting.pkgPrivateFlags
+            if ((systemPkgSetting.pkgPrivateFlags
                     & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0) {
                 scanFlags |= SCAN_AS_VENDOR;
             }
-            if ((disabledPkgSetting.pkgPrivateFlags
+            if ((systemPkgSetting.pkgPrivateFlags
                     & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0) {
                 scanFlags |= SCAN_AS_PRODUCT;
             }
-            if ((disabledPkgSetting.pkgPrivateFlags
+            if ((systemPkgSetting.pkgPrivateFlags
                     & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES) != 0) {
                 scanFlags |= SCAN_AS_PRODUCT_SERVICES;
             }
@@ -10044,11 +10068,18 @@
         final PackageSetting disabledPkgSetting = request.disabledPkgSetting;
         final UserHandle user = request.user;
         final String realPkgName = request.realPkgName;
-        final PackageSetting pkgSetting = result.pkgSetting;
         final List<String> changedAbiCodePath = result.changedAbiCodePath;
-        final boolean newPkgSettingCreated = (result.pkgSetting != request.pkgSetting);
-
-        if (newPkgSettingCreated) {
+        final PackageSetting pkgSetting;
+        if (result.existingSettingCopied) {
+            pkgSetting = request.pkgSetting;
+            pkgSetting.updateFrom(result.pkgSetting);
+            pkg.mExtras = pkgSetting;
+            if (pkgSetting.sharedUser != null
+                    && pkgSetting.sharedUser.removePackage(result.pkgSetting)) {
+                pkgSetting.sharedUser.addPackage(pkgSetting);
+            }
+        } else {
+            pkgSetting = result.pkgSetting;
             if (originalPkgSetting != null) {
                 mSettings.addRenamedPackageLPw(pkg.packageName, originalPkgSetting.name);
             }
@@ -10355,7 +10386,6 @@
         String primaryCpuAbiFromSettings = null;
         String secondaryCpuAbiFromSettings = null;
         boolean needToDeriveAbi = (scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0;
-
         if (!needToDeriveAbi) {
             if (pkgSetting != null) {
                 primaryCpuAbiFromSettings = pkgSetting.primaryCpuAbiString;
@@ -10399,6 +10429,11 @@
                     UserManagerService.getInstance(), usesStaticLibraries,
                     pkg.usesStaticLibrariesVersions);
         } else {
+            if (!createNewPackage) {
+                // make a deep copy to avoid modifying any existing system state.
+                pkgSetting = new PackageSetting(pkgSetting);
+                pkgSetting.pkg = pkg;
+            }
             // REMOVE SharedUserSetting from method; update in a separate call.
             //
             // TODO(narayan): This update is bogus. nativeLibraryDir & primaryCpuAbi,
@@ -10431,8 +10466,10 @@
             final boolean fullApp = (scanFlags & SCAN_AS_FULL_APP) != 0;
             setInstantAppForUser(pkgSetting, userId, instantApp, fullApp);
         }
-
-        if (disabledPkgSetting != null) {
+        // TODO(patb): see if we can do away with disabled check here.
+        if (disabledPkgSetting != null
+                || (0 != (scanFlags & SCAN_NEW_INSTALL)
+                && pkgSetting != null && pkgSetting.isSystem())) {
             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
         }
 
@@ -10615,7 +10652,8 @@
             pkgSetting.volumeUuid = volumeUuid;
         }
 
-        return new ScanResult(request, true, pkgSetting, changedAbiCodePath);
+        return new ScanResult(request, true, pkgSetting, changedAbiCodePath,
+                !createNewPackage /* existingSettingCopied */);
     }
 
     /**
@@ -10830,7 +10868,7 @@
             }
 
             // A package name must be unique; don't allow duplicates
-            if (mPackages.containsKey(pkg.packageName)) {
+            if ((scanFlags & SCAN_NEW_INSTALL) == 0 && mPackages.containsKey(pkg.packageName)) {
                 throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
                         "Application package " + pkg.packageName
                         + " already installed.  Skipping duplicate.");
@@ -10839,7 +10877,8 @@
             if (pkg.applicationInfo.isStaticSharedLibrary()) {
                 // Static libs have a synthetic package name containing the version
                 // but we still want the base name to be unique.
-                if (mPackages.containsKey(pkg.manifestPackageName)) {
+                if ((scanFlags & SCAN_NEW_INSTALL) == 0
+                        && mPackages.containsKey(pkg.manifestPackageName)) {
                     throw new PackageManagerException(
                             "Duplicate static shared lib provider package");
                 }
@@ -11928,7 +11967,9 @@
         // Remove the parent package setting
         PackageSetting ps = (PackageSetting) pkg.mExtras;
         if (ps != null) {
-            removePackageLI(ps, chatty);
+            removePackageLI(ps.name, chatty);
+        } else if (DEBUG_REMOVE && chatty) {
+            Log.d(TAG, "Not removing package " + pkg.packageName + "; mExtras == null");
         }
         // Remove the child package setting
         final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
@@ -11936,23 +11977,22 @@
             PackageParser.Package childPkg = pkg.childPackages.get(i);
             ps = (PackageSetting) childPkg.mExtras;
             if (ps != null) {
-                removePackageLI(ps, chatty);
+                removePackageLI(ps.name, chatty);
             }
         }
     }
 
-    void removePackageLI(PackageSetting ps, boolean chatty) {
+    void removePackageLI(String packageName, boolean chatty) {
         if (DEBUG_INSTALL) {
             if (chatty)
-                Log.d(TAG, "Removing package " + ps.name);
+                Log.d(TAG, "Removing package " + packageName);
         }
 
         // writer
         synchronized (mPackages) {
-            mPackages.remove(ps.name);
-            final PackageParser.Package pkg = ps.pkg;
-            if (pkg != null) {
-                cleanPackageDataStructuresLILPw(pkg, chatty);
+            final PackageParser.Package removedPackage = mPackages.remove(packageName);
+            if (removedPackage != null) {
+                cleanPackageDataStructuresLILPw(removedPackage, chatty);
             }
         }
     }
@@ -14653,68 +14693,6 @@
         String origPermission;
     }
 
-    /*
-     * Install a non-existing package.
-     */
-    private void installNewPackageLIF(PackageParser.Package pkg, final @ParseFlags int parseFlags,
-            final @ScanFlags int scanFlags, UserHandle user, String installerPackageName,
-            String volumeUuid, PackageInstalledInfo res, int installReason) {
-        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installNewPackage");
-
-        // Remember this for later, in case we need to rollback this install
-        String pkgName = pkg.packageName;
-
-        if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
-
-        synchronized(mPackages) {
-            final String renamedPackage = mSettings.getRenamedPackageLPr(pkgName);
-            if (renamedPackage != null) {
-                // A package with the same name is already installed, though
-                // it has been renamed to an older name.  The package we
-                // are trying to install should be installed as an update to
-                // the existing one, but that has not been requested, so bail.
-                res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName
-                        + " without first uninstalling package running as "
-                        + renamedPackage);
-                return;
-            }
-            if (mPackages.containsKey(pkgName)) {
-                // Don't allow installation over an existing package with the same name.
-                res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName
-                        + " without first uninstalling.");
-                return;
-            }
-        }
-
-        try {
-            final PackageParser.Package newPackage;
-            List<ScanResult> scanResults = scanPackageTracedLI(pkg, parseFlags, scanFlags,
-                    System.currentTimeMillis(), user);
-            commitSuccessfulScanResults(scanResults);
-            // TODO(b/109941548): Child packages may return >1 result with the first being the base;
-            // we need to treat child packages as an atomic install and remove this hack
-            final ScanResult basePackageScanResult = scanResults.get(0);
-            newPackage = basePackageScanResult.pkgSetting.pkg;
-            updateSettingsLI(newPackage, installerPackageName, null, res, user, installReason);
-
-            if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
-                prepareAppDataAfterInstallLIF(newPackage);
-            } else {
-                // Remove package from internal structures, but keep around any
-                // data that might have already existed
-                deletePackageLIF(pkgName, UserHandle.ALL, false, null,
-                        PackageManager.DELETE_KEEP_DATA, res.removedInfo, true, null);
-            }
-        } catch (PackageManagerException e) {
-            destroyAppDataLIF(pkg, UserHandle.USER_ALL,
-                    StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
-            destroyAppProfilesLIF(pkg, UserHandle.USER_ALL);
-            res.setError("Package couldn't be installed in " + pkg.codePath, e);
-        }
-
-        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-    }
-
     private static void updateDigest(MessageDigest digest, File file) throws IOException {
         try (DigestInputStream digestStream =
                 new DigestInputStream(new FileInputStream(file), digest)) {
@@ -14722,482 +14700,6 @@
         }
     }
 
-    private void replacePackageLIF(PackageParser.Package pkg, final @ParseFlags int parseFlags,
-            final @ScanFlags int scanFlags, UserHandle user, String installerPackageName,
-            PackageInstalledInfo res, int installReason) {
-        final boolean isInstantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
-
-        final PackageParser.Package oldPackage;
-        final PackageSetting ps;
-        final String pkgName = pkg.packageName;
-        final int[] allUsers;
-        final int[] installedUsers;
-
-        synchronized(mPackages) {
-            oldPackage = mPackages.get(pkgName);
-            if (DEBUG_INSTALL) Slog.d(TAG, "replacePackageLI: new=" + pkg + ", old=" + oldPackage);
-
-            // don't allow upgrade to target a release SDK from a pre-release SDK
-            final boolean oldTargetsPreRelease = oldPackage.applicationInfo.targetSdkVersion
-                    == android.os.Build.VERSION_CODES.CUR_DEVELOPMENT;
-            final boolean newTargetsPreRelease = pkg.applicationInfo.targetSdkVersion
-                    == android.os.Build.VERSION_CODES.CUR_DEVELOPMENT;
-            if (oldTargetsPreRelease
-                    && !newTargetsPreRelease
-                    && ((parseFlags & PackageParser.PARSE_FORCE_SDK) == 0)) {
-                Slog.w(TAG, "Can't install package targeting released sdk");
-                res.setReturnCode(PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE);
-                return;
-            }
-
-            ps = mSettings.mPackages.get(pkgName);
-
-            // verify signatures are valid
-            final KeySetManagerService ksms = mSettings.mKeySetManagerService;
-            if (ksms.shouldCheckUpgradeKeySetLocked(ps, scanFlags)) {
-                if (!ksms.checkUpgradeKeySetLocked(ps, pkg)) {
-                    res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
-                            "New package not signed by keys specified by upgrade-keysets: "
-                                    + pkgName);
-                    return;
-                }
-            } else {
-
-                // default to original signature matching
-                if (!pkg.mSigningDetails.checkCapability(oldPackage.mSigningDetails,
-                        PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
-                                && !oldPackage.mSigningDetails.checkCapability(
-                                        pkg.mSigningDetails,
-                                        PackageParser.SigningDetails.CertCapabilities.ROLLBACK)) {
-                    res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
-                            "New package has a different signature: " + pkgName);
-                    return;
-                }
-            }
-
-            // don't allow a system upgrade unless the upgrade hash matches
-            if (oldPackage.restrictUpdateHash != null && oldPackage.isSystem()) {
-                final byte[] digestBytes;
-                try {
-                    final MessageDigest digest = MessageDigest.getInstance("SHA-512");
-                    updateDigest(digest, new File(pkg.baseCodePath));
-                    if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
-                        for (String path : pkg.splitCodePaths) {
-                            updateDigest(digest, new File(path));
-                        }
-                    }
-                    digestBytes = digest.digest();
-                } catch (NoSuchAlgorithmException | IOException e) {
-                    res.setError(INSTALL_FAILED_INVALID_APK,
-                            "Could not compute hash: " + pkgName);
-                    return;
-                }
-                if (!Arrays.equals(oldPackage.restrictUpdateHash, digestBytes)) {
-                    res.setError(INSTALL_FAILED_INVALID_APK,
-                            "New package fails restrict-update check: " + pkgName);
-                    return;
-                }
-                // retain upgrade restriction
-                pkg.restrictUpdateHash = oldPackage.restrictUpdateHash;
-            }
-
-            // Check for shared user id changes
-            String invalidPackageName =
-                    getParentOrChildPackageChangedSharedUser(oldPackage, pkg);
-            if (invalidPackageName != null) {
-                res.setError(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
-                        "Package " + invalidPackageName + " tried to change user "
-                                + oldPackage.mSharedUserId);
-                return;
-            }
-
-            // check if the new package supports all of the abis which the old package supports
-            boolean oldPkgSupportMultiArch = oldPackage.applicationInfo.secondaryCpuAbi != null;
-            boolean newPkgSupportMultiArch = pkg.applicationInfo.secondaryCpuAbi != null;
-            if (isSystemApp(oldPackage) && oldPkgSupportMultiArch && !newPkgSupportMultiArch) {
-                res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
-                        "Update to package " + pkgName + " doesn't support multi arch");
-                return;
-            }
-
-            // In case of rollback, remember per-user/profile install state
-            allUsers = sUserManager.getUserIds();
-            installedUsers = ps.queryInstalledUsers(allUsers, true);
-
-            // don't allow an upgrade from full to ephemeral
-            if (isInstantApp) {
-                if (user == null || user.getIdentifier() == UserHandle.USER_ALL) {
-                    for (int currentUser : allUsers) {
-                        if (!ps.getInstantApp(currentUser)) {
-                            // can't downgrade from full to instant
-                            Slog.w(TAG, "Can't replace full app with instant app: " + pkgName
-                                    + " for user: " + currentUser);
-                            res.setReturnCode(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
-                            return;
-                        }
-                    }
-                } else if (!ps.getInstantApp(user.getIdentifier())) {
-                    // can't downgrade from full to instant
-                    Slog.w(TAG, "Can't replace full app with instant app: " + pkgName
-                            + " for user: " + user.getIdentifier());
-                    res.setReturnCode(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
-                    return;
-                }
-            }
-        }
-
-        // Update what is removed
-        res.removedInfo = new PackageRemovedInfo(this);
-        res.removedInfo.uid = oldPackage.applicationInfo.uid;
-        res.removedInfo.removedPackage = oldPackage.packageName;
-        res.removedInfo.installerPackageName = ps.installerPackageName;
-        res.removedInfo.isStaticSharedLib = pkg.staticSharedLibName != null;
-        res.removedInfo.isUpdate = true;
-        res.removedInfo.origUsers = installedUsers;
-        res.removedInfo.installReasons = new SparseArray<>(installedUsers.length);
-        for (int i = 0; i < installedUsers.length; i++) {
-            final int userId = installedUsers[i];
-            res.removedInfo.installReasons.put(userId, ps.getInstallReason(userId));
-        }
-
-        final int childCount = (oldPackage.childPackages != null)
-                ? oldPackage.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            boolean childPackageUpdated = false;
-            PackageParser.Package childPkg = oldPackage.childPackages.get(i);
-            final PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
-            if (res.addedChildPackages != null) {
-                PackageInstalledInfo childRes = res.addedChildPackages.get(childPkg.packageName);
-                if (childRes != null) {
-                    childRes.removedInfo.uid = childPkg.applicationInfo.uid;
-                    childRes.removedInfo.removedPackage = childPkg.packageName;
-                    if (childPs != null) {
-                        childRes.removedInfo.installerPackageName = childPs.installerPackageName;
-                    }
-                    childRes.removedInfo.isUpdate = true;
-                    childRes.removedInfo.installReasons = res.removedInfo.installReasons;
-                    childPackageUpdated = true;
-                }
-            }
-            if (!childPackageUpdated) {
-                PackageRemovedInfo childRemovedRes = new PackageRemovedInfo(this);
-                childRemovedRes.removedPackage = childPkg.packageName;
-                if (childPs != null) {
-                    childRemovedRes.installerPackageName = childPs.installerPackageName;
-                }
-                childRemovedRes.isUpdate = false;
-                childRemovedRes.dataRemoved = true;
-                synchronized (mPackages) {
-                    if (childPs != null) {
-                        childRemovedRes.origUsers = childPs.queryInstalledUsers(allUsers, true);
-                    }
-                }
-                if (res.removedInfo.removedChildPackages == null) {
-                    res.removedInfo.removedChildPackages = new ArrayMap<>();
-                }
-                res.removedInfo.removedChildPackages.put(childPkg.packageName, childRemovedRes);
-            }
-        }
-
-        boolean sysPkg = (isSystemApp(oldPackage));
-        if (sysPkg) {
-            // Set the system/privileged/oem/vendor/product flags as needed
-            final boolean privileged = isPrivilegedApp(oldPackage);
-            final boolean oem = isOemApp(oldPackage);
-            final boolean vendor = isVendorApp(oldPackage);
-            final boolean product = isProductApp(oldPackage);
-            final boolean productServices = isProductServicesApp(oldPackage);
-
-            final @ParseFlags int systemParseFlags = parseFlags;
-            final @ScanFlags int systemScanFlags = scanFlags
-                    | SCAN_AS_SYSTEM
-                    | (privileged ? SCAN_AS_PRIVILEGED : 0)
-                    | (oem ? SCAN_AS_OEM : 0)
-                    | (vendor ? SCAN_AS_VENDOR : 0)
-                    | (product ? SCAN_AS_PRODUCT : 0)
-                    | (productServices ? SCAN_AS_PRODUCT_SERVICES : 0);
-
-            replaceSystemPackageLIF(oldPackage, pkg, systemParseFlags, systemScanFlags,
-                    user, allUsers, installerPackageName, res, installReason);
-        } else {
-            replaceNonSystemPackageLIF(oldPackage, pkg, parseFlags, scanFlags,
-                    user, allUsers, installerPackageName, res, installReason);
-        }
-    }
-
-    private void replaceNonSystemPackageLIF(PackageParser.Package deletedPackage,
-            PackageParser.Package pkg, final @ParseFlags int parseFlags,
-            final @ScanFlags int scanFlags, UserHandle user, int[] allUsers,
-            String installerPackageName, PackageInstalledInfo res, int installReason) {
-        if (DEBUG_INSTALL) Slog.d(TAG, "replaceNonSystemPackageLI: new=" + pkg + ", old="
-                + deletedPackage);
-
-        String pkgName = deletedPackage.packageName;
-        boolean deletedPkg = true;
-        boolean addedPkg = false;
-        boolean updatedSettings = false;
-        final boolean killApp = (scanFlags & SCAN_DONT_KILL_APP) == 0;
-        final int deleteFlags = PackageManager.DELETE_KEEP_DATA
-                | (killApp ? 0 : PackageManager.DELETE_DONT_KILL_APP);
-
-        final long origUpdateTime = (pkg.mExtras != null)
-                ? ((PackageSetting)pkg.mExtras).lastUpdateTime : 0;
-
-        // First delete the existing package while retaining the data directory
-        if (!deletePackageLIF(pkgName, null, true, allUsers, deleteFlags,
-                res.removedInfo, true, pkg)) {
-            // If the existing package wasn't successfully deleted
-            res.setError(INSTALL_FAILED_REPLACE_COULDNT_DELETE, "replaceNonSystemPackageLI");
-            deletedPkg = false;
-        } else {
-            // Successfully deleted the old package; proceed with replace.
-
-            // If deleted package lived in a container, give users a chance to
-            // relinquish resources before killing.
-            if (deletedPackage.isForwardLocked() || isExternal(deletedPackage)) {
-                if (DEBUG_INSTALL) {
-                    Slog.i(TAG, "upgrading pkg " + deletedPackage + " is ASEC-hosted -> UNAVAILABLE");
-                }
-                final int[] uidArray = new int[] { deletedPackage.applicationInfo.uid };
-                final ArrayList<String> pkgList = new ArrayList<>(1);
-                pkgList.add(deletedPackage.applicationInfo.packageName);
-                sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);
-            }
-
-            clearAppDataLIF(pkg, UserHandle.USER_ALL, StorageManager.FLAG_STORAGE_DE
-                    | StorageManager.FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
-
-            try {
-                final List<ScanResult> scanResults = scanPackageTracedLI(pkg, parseFlags,
-                        scanFlags | SCAN_UPDATE_TIME, System.currentTimeMillis(), user);
-                commitSuccessfulScanResults(scanResults);
-                final PackageParser.Package newPackage = scanResults.get(0).pkgSetting.pkg;
-                updateSettingsLI(newPackage, installerPackageName, allUsers, res, user,
-                        installReason);
-
-                // Update the in-memory copy of the previous code paths.
-                PackageSetting ps = mSettings.mPackages.get(pkgName);
-                if (!killApp) {
-                    if (ps.oldCodePaths == null) {
-                        ps.oldCodePaths = new ArraySet<>();
-                    }
-                    Collections.addAll(ps.oldCodePaths, deletedPackage.baseCodePath);
-                    if (deletedPackage.splitCodePaths != null) {
-                        Collections.addAll(ps.oldCodePaths, deletedPackage.splitCodePaths);
-                    }
-                } else {
-                    ps.oldCodePaths = null;
-                }
-                if (ps.childPackageNames != null) {
-                    for (int i = ps.childPackageNames.size() - 1; i >= 0; --i) {
-                        final String childPkgName = ps.childPackageNames.get(i);
-                        final PackageSetting childPs = mSettings.mPackages.get(childPkgName);
-                        childPs.oldCodePaths = ps.oldCodePaths;
-                    }
-                }
-                prepareAppDataAfterInstallLIF(newPackage);
-                addedPkg = true;
-                mDexManager.notifyPackageUpdated(newPackage.packageName,
-                        newPackage.baseCodePath, newPackage.splitCodePaths);
-            } catch (PackageManagerException e) {
-                res.setError("Package couldn't be installed in " + pkg.codePath, e);
-            }
-        }
-
-        if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
-            if (DEBUG_INSTALL) Slog.d(TAG, "Install failed, rolling pack: " + pkgName);
-
-            // Revert all internal state mutations and added folders for the failed install
-            if (addedPkg) {
-                deletePackageLIF(pkgName, null, true, allUsers, deleteFlags,
-                        res.removedInfo, true, null);
-            }
-
-            // Restore the old package
-            if (deletedPkg) {
-                if (DEBUG_INSTALL) Slog.d(TAG, "Install failed, reinstalling: " + deletedPackage);
-                File restoreFile = new File(deletedPackage.codePath);
-                // Parse old package
-                boolean oldExternal = isExternal(deletedPackage);
-                int oldParseFlags  = mDefParseFlags | PackageParser.PARSE_CHATTY |
-                        (deletedPackage.isForwardLocked() ? PackageParser.PARSE_FORWARD_LOCK : 0) |
-                        (oldExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);
-                int oldScanFlags = SCAN_UPDATE_SIGNATURE | SCAN_UPDATE_TIME;
-                try {
-                    scanPackageTracedLI(restoreFile, oldParseFlags, oldScanFlags, origUpdateTime,
-                            null);
-                } catch (PackageManagerException e) {
-                    Slog.e(TAG, "Failed to restore package : " + pkgName + " after failed upgrade: "
-                            + e.getMessage());
-                    return;
-                }
-
-                synchronized (mPackages) {
-                    // Ensure the installer package name up to date
-                    setInstallerPackageNameLPw(deletedPackage, installerPackageName);
-
-                    // Update permissions for restored package
-                    mPermissionManager.updatePermissions(
-                            deletedPackage.packageName, deletedPackage, false, mPackages.values(),
-                            mPermissionCallback);
-
-                    mSettings.writeLPr();
-                }
-
-                Slog.i(TAG, "Successfully restored package : " + pkgName + " after failed upgrade");
-            }
-        } else {
-            synchronized (mPackages) {
-                PackageSetting ps = mSettings.getPackageLPr(pkg.packageName);
-                if (ps != null) {
-                    res.removedInfo.removedForAllUsers = mPackages.get(ps.name) == null;
-                    if (res.removedInfo.removedChildPackages != null) {
-                        final int childCount = res.removedInfo.removedChildPackages.size();
-                        // Iterate in reverse as we may modify the collection
-                        for (int i = childCount - 1; i >= 0; i--) {
-                            String childPackageName = res.removedInfo.removedChildPackages.keyAt(i);
-                            if (res.addedChildPackages.containsKey(childPackageName)) {
-                                res.removedInfo.removedChildPackages.removeAt(i);
-                            } else {
-                                PackageRemovedInfo childInfo = res.removedInfo
-                                        .removedChildPackages.valueAt(i);
-                                childInfo.removedForAllUsers = mPackages.get(
-                                        childInfo.removedPackage) == null;
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    private void replaceSystemPackageLIF(PackageParser.Package deletedPackage,
-            PackageParser.Package pkg, final @ParseFlags int parseFlags,
-            final @ScanFlags int scanFlags, UserHandle user,
-            int[] allUsers, String installerPackageName, PackageInstalledInfo res,
-            int installReason) {
-        if (DEBUG_INSTALL) Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg
-                + ", old=" + deletedPackage);
-
-        final boolean disabledSystem;
-
-        // Remove existing system package
-        removePackageLI(deletedPackage, true);
-
-        synchronized (mPackages) {
-            disabledSystem = disableSystemPackageLPw(deletedPackage, pkg);
-        }
-        if (!disabledSystem) {
-            // We didn't need to disable the .apk as a current system package,
-            // which means we are replacing another update that is already
-            // installed.  We need to make sure to delete the older one's .apk.
-            res.removedInfo.args = createInstallArgsForExisting(0,
-                    deletedPackage.applicationInfo.getCodePath(),
-                    deletedPackage.applicationInfo.getResourcePath(),
-                    getAppDexInstructionSets(deletedPackage.applicationInfo));
-        } else {
-            res.removedInfo.args = null;
-        }
-
-        // Successfully disabled the old package. Now proceed with re-installation
-        clearAppDataLIF(pkg, UserHandle.USER_ALL, StorageManager.FLAG_STORAGE_DE
-                | StorageManager.FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
-
-        res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
-        pkg.setApplicationInfoFlags(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP,
-                ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
-
-        PackageParser.Package newPackage = null;
-        try {
-            final List<ScanResult> scanResults =
-                    scanPackageTracedLI(pkg, parseFlags, scanFlags, 0, user);
-            // Add the package to the internal data structures
-            commitSuccessfulScanResults(scanResults);
-            newPackage = scanResults.get(0).pkgSetting.pkg;
-
-            // Set the update and install times
-            PackageSetting deletedPkgSetting = (PackageSetting) deletedPackage.mExtras;
-            setInstallAndUpdateTime(newPackage, deletedPkgSetting.firstInstallTime,
-                    System.currentTimeMillis());
-
-            // Update the package dynamic state if succeeded
-            if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
-                // Now that the install succeeded make sure we remove data
-                // directories for any child package the update removed.
-                final int deletedChildCount = (deletedPackage.childPackages != null)
-                        ? deletedPackage.childPackages.size() : 0;
-                final int newChildCount = (newPackage.childPackages != null)
-                        ? newPackage.childPackages.size() : 0;
-                for (int i = 0; i < deletedChildCount; i++) {
-                    PackageParser.Package deletedChildPkg = deletedPackage.childPackages.get(i);
-                    boolean childPackageDeleted = true;
-                    for (int j = 0; j < newChildCount; j++) {
-                        PackageParser.Package newChildPkg = newPackage.childPackages.get(j);
-                        if (deletedChildPkg.packageName.equals(newChildPkg.packageName)) {
-                            childPackageDeleted = false;
-                            break;
-                        }
-                    }
-                    if (childPackageDeleted) {
-                        PackageSetting ps = mSettings.getDisabledSystemPkgLPr(
-                                deletedChildPkg.packageName);
-                        if (ps != null && res.removedInfo.removedChildPackages != null) {
-                            PackageRemovedInfo removedChildRes = res.removedInfo
-                                    .removedChildPackages.get(deletedChildPkg.packageName);
-                            removePackageDataLIF(ps, allUsers, removedChildRes, 0, false);
-                            removedChildRes.removedForAllUsers = mPackages.get(ps.name) == null;
-                        }
-                    }
-                }
-
-                updateSettingsLI(newPackage, installerPackageName, allUsers, res, user,
-                        installReason);
-                prepareAppDataAfterInstallLIF(newPackage);
-
-                mDexManager.notifyPackageUpdated(newPackage.packageName,
-                            newPackage.baseCodePath, newPackage.splitCodePaths);
-            }
-        } catch (PackageManagerException e) {
-            res.setReturnCode(INSTALL_FAILED_INTERNAL_ERROR);
-            res.setError("Package couldn't be installed in " + pkg.codePath, e);
-        }
-
-        if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
-            // Re installation failed. Restore old information
-            // Remove new pkg information
-            if (newPackage != null) {
-                removeInstalledPackageLI(newPackage, true);
-            }
-            // Add back the old system package
-            try {
-                final List<ScanResult> scanResults = scanPackageTracedLI(
-                        deletedPackage, parseFlags, SCAN_UPDATE_SIGNATURE, 0, user);
-                commitSuccessfulScanResults(scanResults);
-            } catch (PackageManagerException e) {
-                Slog.e(TAG, "Failed to restore original package: " + e.getMessage());
-            }
-
-            synchronized (mPackages) {
-                if (disabledSystem) {
-                    enableSystemPackageLPw(deletedPackage);
-                }
-
-                // Ensure the installer package name up to date
-                setInstallerPackageNameLPw(deletedPackage, installerPackageName);
-
-                // Update permissions for restored package
-                mPermissionManager.updatePermissions(
-                        deletedPackage.packageName, deletedPackage, false, mPackages.values(),
-                        mPermissionCallback);
-
-                mSettings.writeLPr();
-            }
-
-            Slog.i(TAG, "Successfully restored package : " + deletedPackage.packageName
-                    + " after failed upgrade");
-        }
-    }
-
     /**
      * Checks whether the parent or any of the child packages have a change shared
      * user. For a package to be a valid update the shred users of the parent and
@@ -15394,92 +14896,685 @@
 
         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
     }
+
     private static class InstallRequest {
-        final InstallArgs args;
-        final PackageInstalledInfo res;
+        public final InstallArgs args;
+        public final PackageInstalledInfo installResult;
 
         private InstallRequest(InstallArgs args, PackageInstalledInfo res) {
             this.args = args;
-            this.res = res;
+            this.installResult = res;
         }
     }
 
     @GuardedBy({"mInstallLock", "mPackages"})
-    private void installPackageTracedLI(InstallArgs args, PackageInstalledInfo res) {
+    private void installPackageTracedLI(InstallArgs args, PackageInstalledInfo installResult) {
         try {
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackage");
-            installPackagesLI(Collections.singletonList(new InstallRequest(args, res)));
+            installPackagesLI(Collections.singletonList(new InstallRequest(args, installResult)));
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
     }
 
+    /**
+     * Package state to commit to memory and disk after reconciliation has completed.
+     */
     private static class CommitRequest {
         final Map<String, ReconciledPackage> reconciledPackages;
+        final int[] mAllUsers;
 
-        private CommitRequest(Map<String, ReconciledPackage> reconciledPackages) {
+        private CommitRequest(Map<String, ReconciledPackage> reconciledPackages, int[] allUsers) {
             this.reconciledPackages = reconciledPackages;
+            this.mAllUsers = allUsers;
         }
     }
-    private static class ReconcileRequest {
-        final Map<String, ScanResult> scannedPackages;
 
-        private ReconcileRequest(Map<String, ScanResult> scannedPackages) {
+    /**
+     * Package scan results and related request details used to reconcile the potential addition of
+     * one or more packages to the system.
+     *
+     * Reconcile will take a set of package details that need to be committed to the system and make
+     * sure that they are valid in the context of the system and the other installing apps. Any
+     * invalid state or app will result in a failed reconciliation and thus whatever operation (such
+     * as install) led to the request.
+     */
+    private static class ReconcileRequest {
+        public final Map<String, ScanResult> scannedPackages;
+
+        // TODO: Remove install-specific details from reconcile request; make them generic types
+        //       that can be used for scanDir for example.
+        public final Map<String, InstallArgs> installArgs;
+        public final Map<String, PackageInstalledInfo> installResults;
+        public final Map<String, PrepareResult> preparedPackages;
+
+        private ReconcileRequest(Map<String, ScanResult> scannedPackages,
+                Map<String, InstallArgs> installArgs,
+                Map<String, PackageInstalledInfo> installResults,
+                Map<String, PrepareResult> preparedPackages) {
             this.scannedPackages = scannedPackages;
+            this.installArgs = installArgs;
+            this.installResults = installResults;
+            this.preparedPackages = preparedPackages;
         }
     }
     private static class ReconcileFailure extends PackageManagerException {
         public ReconcileFailure(String message) {
             super("Invalid reconcile request: " + message);
         }
-    };
+    }
 
     /**
      * A container of all data needed to commit a package to in-memory data structures and to disk.
-     * Ideally most of the data contained in this class will move into a PackageSetting it contains.
+     * TODO: move most of the data contained her into a PackageSetting for commit.
      */
-    private static class ReconciledPackage {}
+    private static class ReconciledPackage {
+        public final PackageSetting pkgSetting;
+        public final ScanResult scanResult;
+        public final UserHandle installForUser;
+        public final String volumeUuid;
+        // TODO: Remove install-specific details from the reconcile result
+        public final PackageInstalledInfo installResult;
+        public final PrepareResult prepareResult;
+        @PackageManager.InstallFlags
+        public final int installFlags;
+        public final InstallArgs installArgs;
+
+        private ReconciledPackage(InstallArgs installArgs, PackageSetting pkgSetting,
+                UserHandle installForUser, PackageInstalledInfo installResult, int installFlags,
+                String volumeUuid, PrepareResult prepareResult, ScanResult scanResult) {
+            this.installArgs = installArgs;
+            this.pkgSetting = pkgSetting;
+            this.installForUser = installForUser;
+            this.installResult = installResult;
+            this.installFlags = installFlags;
+            this.volumeUuid = volumeUuid;
+            this.prepareResult = prepareResult;
+            this.scanResult = scanResult;
+        }
+    }
 
     @GuardedBy("mPackages")
     private static Map<String, ReconciledPackage> reconcilePackagesLocked(
-            final ReconcileRequest request) throws ReconcileFailure {
-        return Collections.emptyMap();
+            final ReconcileRequest request)
+            throws ReconcileFailure {
+        Map<String, ReconciledPackage> result = new ArrayMap<>(request.scannedPackages.size());
+        for (String installPackageName : request.installArgs.keySet()) {
+            final ScanResult scanResult = request.scannedPackages.get(installPackageName);
+            final InstallArgs installArgs = request.installArgs.get(installPackageName);
+            final PackageInstalledInfo res = request.installResults.get(installPackageName);
+            if (scanResult == null || installArgs == null || res == null) {
+                throw new ReconcileFailure(
+                        "inputs not balanced; missing argument for " + installPackageName);
+            }
+            result.put(installPackageName,
+                    new ReconciledPackage(installArgs, scanResult.pkgSetting, installArgs.getUser(),
+                            res, installArgs.installFlags, installArgs.volumeUuid,
+                            request.preparedPackages.get(installPackageName), scanResult));
+        }
+        return result;
     }
 
     @GuardedBy("mPackages")
     private boolean commitPackagesLocked(final CommitRequest request) {
+        // TODO: remove any expected failures from this method; this should only be able to fail due
+        //       to unavoidable errors (I/O, etc.)
+        for (ReconciledPackage reconciledPkg : request.reconciledPackages.values()) {
+            final ScanResult scanResult = reconciledPkg.scanResult;
+            final ScanRequest scanRequest = scanResult.request;
+            final PackageParser.Package pkg = scanRequest.pkg;
+            final String packageName = pkg.packageName;
+            final PackageInstalledInfo res = reconciledPkg.installResult;
+
+            if (reconciledPkg.prepareResult.replace) {
+                PackageParser.Package oldPackage = mPackages.get(packageName);
+                if (reconciledPkg.prepareResult.system) {
+                    // Remove existing system package
+                    removePackageLI(oldPackage, true);
+                    if (!disableSystemPackageLPw(oldPackage, pkg)) {
+                        // We didn't need to disable the .apk as a current system package,
+                        // which means we are replacing another update that is already
+                        // installed.  We need to make sure to delete the older one's .apk.
+                        res.removedInfo.args = createInstallArgsForExisting(0,
+                                oldPackage.applicationInfo.getCodePath(),
+                                oldPackage.applicationInfo.getResourcePath(),
+                                getAppDexInstructionSets(oldPackage.applicationInfo));
+                    } else {
+                        res.removedInfo.args = null;
+                    }
+
+                    // Set the update and install times
+                    PackageSetting deletedPkgSetting = (PackageSetting) oldPackage.mExtras;
+                    setInstallAndUpdateTime(pkg, deletedPkgSetting.firstInstallTime,
+                            System.currentTimeMillis());
+
+                    // Update the package dynamic state if succeeded
+                    // Now that the install succeeded make sure we remove data
+                    // directories for any child package the update removed.
+                    final int deletedChildCount = (oldPackage.childPackages != null)
+                            ? oldPackage.childPackages.size() : 0;
+                    final int newChildCount = (pkg.childPackages != null)
+                            ? pkg.childPackages.size() : 0;
+                    for (int i = 0; i < deletedChildCount; i++) {
+                        PackageParser.Package deletedChildPkg = oldPackage.childPackages.get(i);
+                        boolean childPackageDeleted = true;
+                        for (int j = 0; j < newChildCount; j++) {
+                            PackageParser.Package newChildPkg = pkg.childPackages.get(j);
+                            if (deletedChildPkg.packageName.equals(newChildPkg.packageName)) {
+                                childPackageDeleted = false;
+                                break;
+                            }
+                        }
+                        if (childPackageDeleted) {
+                            PackageSetting ps1 = mSettings.getDisabledSystemPkgLPr(
+                                    deletedChildPkg.packageName);
+                            if (ps1 != null && res.removedInfo.removedChildPackages != null) {
+                                PackageRemovedInfo removedChildRes = res.removedInfo
+                                        .removedChildPackages.get(deletedChildPkg.packageName);
+                                removePackageDataLIF(ps1, request.mAllUsers, removedChildRes, 0,
+                                        false);
+                                removedChildRes.removedForAllUsers = mPackages.get(ps1.name)
+                                        == null;
+                            }
+                        }
+                    }
+                } else {
+                    final boolean killApp = (scanRequest.scanFlags & SCAN_DONT_KILL_APP) == 0;
+                    final int deleteFlags = PackageManager.DELETE_KEEP_DATA
+                            | (killApp ? 0 : PackageManager.DELETE_DONT_KILL_APP);
+                    // First delete the existing package while retaining the data directory
+                    if (!deletePackageLIF(packageName, null, true, request.mAllUsers, deleteFlags,
+                            res.removedInfo, true, pkg)) {
+                        // If the existing package wasn't successfully deleted
+                        res.setError(INSTALL_FAILED_REPLACE_COULDNT_DELETE,
+                                "replaceNonSystemPackageLI");
+                        return false;
+                    } else {
+                        // Successfully deleted the old package; proceed with replace.
+
+                        // If deleted package lived in a container, give users a chance to
+                        // relinquish resources before killing.
+                        if (oldPackage.isForwardLocked() || isExternal(oldPackage)) {
+                            if (DEBUG_INSTALL) {
+                                Slog.i(TAG, "upgrading pkg " + oldPackage
+                                        + " is ASEC-hosted -> UNAVAILABLE");
+                            }
+                            final int[] uidArray = new int[]{oldPackage.applicationInfo.uid};
+                            final ArrayList<String> pkgList = new ArrayList<>(1);
+                            pkgList.add(oldPackage.applicationInfo.packageName);
+                            sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);
+                        }
+
+                        clearAppDataLIF(pkg, UserHandle.USER_ALL, StorageManager.FLAG_STORAGE_DE
+                                | StorageManager.FLAG_STORAGE_CE
+                                | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
+                    }
+
+
+
+                    // Update the in-memory copy of the previous code paths.
+                    PackageSetting ps1 = mSettings.mPackages.get(
+                            reconciledPkg.prepareResult.existingPackage.packageName);
+                    if ((reconciledPkg.installArgs.installFlags & PackageManager.DONT_KILL_APP)
+                            == 0) {
+                        if (ps1.mOldCodePaths == null) {
+                            ps1.mOldCodePaths = new ArraySet<>();
+                        }
+                        Collections.addAll(ps1.mOldCodePaths, oldPackage.baseCodePath);
+                        if (oldPackage.splitCodePaths != null) {
+                            Collections.addAll(ps1.mOldCodePaths, oldPackage.splitCodePaths);
+                        }
+                    } else {
+                        ps1.mOldCodePaths = null;
+                    }
+                    if (ps1.childPackageNames != null) {
+                        for (int i = ps1.childPackageNames.size() - 1; i >= 0; --i) {
+                            final String childPkgName = ps1.childPackageNames.get(i);
+                            final PackageSetting childPs = mSettings.mPackages.get(childPkgName);
+                            childPs.mOldCodePaths = ps1.mOldCodePaths;
+                        }
+                    }
+
+                    if (reconciledPkg.installResult.returnCode
+                            == PackageManager.INSTALL_SUCCEEDED) {
+                        PackageSetting ps2 = mSettings.getPackageLPr(pkg.packageName);
+                        if (ps2 != null) {
+                            res.removedInfo.removedForAllUsers = mPackages.get(ps2.name) == null;
+                            if (res.removedInfo.removedChildPackages != null) {
+                                final int childCount1 = res.removedInfo.removedChildPackages.size();
+                                // Iterate in reverse as we may modify the collection
+                                for (int i = childCount1 - 1; i >= 0; i--) {
+                                    String childPackageName =
+                                            res.removedInfo.removedChildPackages.keyAt(i);
+                                    if (res.addedChildPackages.containsKey(childPackageName)) {
+                                        res.removedInfo.removedChildPackages.removeAt(i);
+                                    } else {
+                                        PackageRemovedInfo childInfo = res.removedInfo
+                                                .removedChildPackages.valueAt(i);
+                                        childInfo.removedForAllUsers = mPackages.get(
+                                                childInfo.removedPackage) == null;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+
+
+            try {
+                commitScanResultLocked(scanResult);
+            } catch (PackageManagerException e) {
+                res.setReturnCode(INSTALL_FAILED_INTERNAL_ERROR);
+                res.setError("Package couldn't be installed in " + pkg.codePath, e);
+                return false;
+            }
+            updateSettingsLI(pkg, reconciledPkg.installArgs.installerPackageName, request.mAllUsers,
+                    res, reconciledPkg.installForUser, reconciledPkg.installArgs.installReason);
+
+            final PackageSetting ps = mSettings.mPackages.get(packageName);
+            if (ps != null) {
+                res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
+                ps.setUpdateAvailable(false /*updateAvailable*/);
+            }
+            final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
+            for (int i = 0; i < childCount; i++) {
+                PackageParser.Package childPkg = pkg.childPackages.get(i);
+                PackageInstalledInfo childRes = res.addedChildPackages.get(
+                        childPkg.packageName);
+                PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
+                if (childPs != null) {
+                    childRes.newUsers = childPs.queryInstalledUsers(
+                            sUserManager.getUserIds(), true);
+                }
+            }
+            if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
+                updateSequenceNumberLP(ps, res.newUsers);
+                updateInstantAppInstallerLocked(packageName);
+            }
+        }
         return true;
     }
 
-    @GuardedBy({"mInstallLock", "mPackages", "PackageManagerService.mPackages"})
+    /**
+     * Installs one or more packages atomically. This operation is broken up into four phases:
+     * <ul>
+     *     <li><b>Prepare</b>
+     *         <br/>Analyzes any current install state, parses the package and does initial
+     *         validation on it.</li>
+     *     <li><b>Scan</b>
+     *         <br/>Interrogates the parsed packages given the context collected in prepare.</li>
+     *     <li><b>Reconcile</b>
+     *         <br/>Validates scanned packages in the context of each other and the current system
+     *         state to ensure that the install will be successful.
+     *     <li><b>Commit</b>
+     *         <br/>Commits all scanned packages and updates system state. This is the only place
+     *         that system state may be modified in the install flow and all predictable errors
+     *         must be determined before this phase.</li>
+     * </ul>
+     *
+     * Failure at any phase will result in a full failure to install all packages.
+     */
+    @GuardedBy({"mInstallLock", "mPackages"})
     private void installPackagesLI(List<InstallRequest> requests) {
-        Map<String, ScanResult> scans = new ArrayMap<>(requests.size());
-        for (InstallRequest request : requests) {
-            // TODO(b/109941548): remove this once we've pulled everything from it and into scan,
-            // reconcile or commit.
-            preparePackageLI(request.args, request.res);
-
-            // TODO(b/109941548): scan package and get result
-        }
-        ReconcileRequest reconcileRequest = new ReconcileRequest(scans);
-        Map<String, ReconciledPackage> reconciledPackages;
+        final Map<String, ScanResult> scans = new ArrayMap<>(requests.size());
+        final Map<String, InstallArgs> installArgs = new ArrayMap<>(requests.size());
+        final Map<String, PackageInstalledInfo> installResults = new ArrayMap<>(requests.size());
+        final Map<String, PrepareResult> prepareResults = new ArrayMap<>(requests.size());
         try {
-            reconciledPackages = reconcilePackagesLocked(reconcileRequest);
-        } catch (ReconcileFailure e) {
-            // TODO(b/109941548): set install args error
-            return;
+            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI");
+            for (InstallRequest request : requests) {
+                // TODO(b/109941548): remove this once we've pulled everything from it and into
+                //                    scan, reconcile or commit.
+                final PrepareResult prepareResult;
+                try {
+                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
+                    prepareResult = preparePackageLI(request.args, request.installResult);
+                } catch (PrepareFailure prepareFailure) {
+                    request.installResult.setError(prepareFailure.error,
+                            prepareFailure.getMessage());
+                    request.installResult.origPackage = prepareFailure.conflictingPackage;
+                    request.installResult.origPermission = prepareFailure.conflictingPermission;
+                    return;
+                } finally {
+                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+                }
+                request.installResult.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
+                request.installResult.installerPackageName = request.args.installerPackageName;
+
+                final String packageName = prepareResult.packageToScan.packageName;
+                prepareResults.put(packageName, prepareResult);
+                installResults.put(packageName, request.installResult);
+                installArgs.put(packageName, request.args);
+                try {
+                    final List<ScanResult> scanResults = scanPackageTracedLI(
+                            prepareResult.packageToScan, prepareResult.parseFlags,
+                            prepareResult.scanFlags, System.currentTimeMillis(),
+                            request.args.user);
+                    for (ScanResult result : scanResults) {
+                        if (null != scans.put(result.pkgSetting.pkg.packageName, result)) {
+                            request.installResult.setError(
+                                    PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
+                                    "Duplicate package " + result.pkgSetting.pkg.packageName
+                                            + " in atomic install request.");
+                            return;
+                        }
+                    }
+                } catch (PackageManagerException e) {
+                    request.installResult.setError("Scanning Failed.", e);
+                    return;
+                }
+            }
+            ReconcileRequest reconcileRequest = new ReconcileRequest(scans, installArgs,
+                    installResults,
+                    prepareResults);
+            CommitRequest commitRequest = null;
+            synchronized (mPackages) {
+                Map<String, ReconciledPackage> reconciledPackages;
+                try {
+                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
+                    reconciledPackages = reconcilePackagesLocked(reconcileRequest);
+                } catch (ReconcileFailure e) {
+                    for (InstallRequest request : requests) {
+                        // TODO(b/109941548): add more concrete failure reasons
+                        request.installResult.setError("Reconciliation failed...", e);
+                        // TODO: return any used system resources
+                    }
+                    return;
+                } finally {
+                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+                }
+                try {
+                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
+                    commitRequest = new CommitRequest(reconciledPackages,
+                            sUserManager.getUserIds());
+                    if (!commitPackagesLocked(commitRequest)) {
+                        cleanUpCommitFailuresLocked(commitRequest);
+                        return;
+                    }
+                } finally {
+                    for (PrepareResult result : prepareResults.values()) {
+                        if (result.freezer != null) {
+                            result.freezer.close();
+                        }
+                    }
+                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+                }
+            }
+            executePostCommitSteps(commitRequest);
+        } finally {
+            for (PrepareResult result : prepareResults.values()) {
+                if (result.freezer != null) {
+                    result.freezer.close();
+                }
+            }
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
-        CommitRequest request = new CommitRequest(reconciledPackages);
-        if (!commitPackagesLocked(request)) {
-            // TODO(b/109941548): set install args error
-            return;
-        }
-        // TODO(b/109941548) post-commit actions (dex-opt, etc.)
     }
 
-    @Deprecated
+    /**
+     * On successful install, executes remaining steps after commit completes and the package lock
+     * is released.
+     */
+    private void executePostCommitSteps(CommitRequest commitRequest) {
+        for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {
+            final boolean forwardLocked =
+                    ((reconciledPkg.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
+            final boolean instantApp =
+                    ((reconciledPkg.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0);
+            final PackageParser.Package pkg = reconciledPkg.pkgSetting.pkg;
+            final String packageName = pkg.packageName;
+            prepareAppDataAfterInstallLIF(pkg);
+            if (reconciledPkg.prepareResult.clearCodeCache) {
+                clearAppDataLIF(pkg, UserHandle.USER_ALL, StorageManager.FLAG_STORAGE_DE
+                        | StorageManager.FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
+            }
+            if (reconciledPkg.prepareResult.replace) {
+                mDexManager.notifyPackageUpdated(pkg.packageName,
+                        pkg.baseCodePath, pkg.splitCodePaths);
+            }
+
+            // Prepare the application profiles for the new code paths.
+            // This needs to be done before invoking dexopt so that any install-time profile
+            // can be used for optimizations.
+            mArtManagerService.prepareAppProfiles(
+                    pkg,
+                    resolveUserIds(reconciledPkg.installForUser.getIdentifier()),
+                    /* updateReferenceProfileContent= */ true);
+
+            // Check whether we need to dexopt the app.
+            //
+            // NOTE: it is IMPORTANT to call dexopt:
+            //   - after doRename which will sync the package data from PackageParser.Package and
+            //     its corresponding ApplicationInfo.
+            //   - after installNewPackageLIF or replacePackageLIF which will update result with the
+            //     uid of the application (pkg.applicationInfo.uid).
+            //     This update happens in place!
+            //
+            // We only need to dexopt if the package meets ALL of the following conditions:
+            //   1) it is not forward locked.
+            //   2) it is not on on an external ASEC container.
+            //   3) it is not an instant app or if it is then dexopt is enabled via gservices.
+            //   4) it is not debuggable.
+            //
+            // Note that we do not dexopt instant apps by default. dexopt can take some time to
+            // complete, so we skip this step during installation. Instead, we'll take extra time
+            // the first time the instant app starts. It's preferred to do it this way to provide
+            // continuous progress to the useur instead of mysteriously blocking somewhere in the
+            // middle of running an instant app. The default behaviour can be overridden
+            // via gservices.
+            final boolean performDexopt = !forwardLocked
+                    && !pkg.applicationInfo.isExternalAsec()
+                    && (!instantApp || Global.getInt(mContext.getContentResolver(),
+                    Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
+                    && ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0);
+
+            if (performDexopt) {
+                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
+                // Do not run PackageDexOptimizer through the local performDexOpt
+                // method because `pkg` may not be in `mPackages` yet.
+                //
+                // Also, don't fail application installs if the dexopt step fails.
+                DexoptOptions dexoptOptions = new DexoptOptions(packageName,
+                        REASON_INSTALL,
+                        DexoptOptions.DEXOPT_BOOT_COMPLETE
+                                | DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE);
+                mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
+                        null /* instructionSets */,
+                        getOrCreateCompilerPackageStats(pkg),
+                        mDexManager.getPackageUseInfoOrDefault(packageName),
+                        dexoptOptions);
+                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+            }
+
+            // Notify BackgroundDexOptService that the package has been changed.
+            // If this is an update of a package which used to fail to compile,
+            // BackgroundDexOptService will remove it from its blacklist.
+            // TODO: Layering violation
+            BackgroundDexOptService.notifyPackageChanged(packageName);
+        }
+
+    }
+
+    private void cleanUpCommitFailuresLocked(CommitRequest request) {
+        final Map<String, ReconciledPackage> reconciledPackages = request.reconciledPackages;
+        final int[] allUsers = request.mAllUsers;
+        for (ReconciledPackage reconciledPackage : reconciledPackages.values()) {
+            final String pkgName1 = reconciledPackage.pkgSetting.pkg.packageName;
+            if (reconciledPackage.installResult.returnCode == PackageManager.INSTALL_SUCCEEDED) {
+                reconciledPackage.installResult.setError(
+                        PackageManager.INSTALL_FAILED_INTERNAL_ERROR, "Commit failed...");
+            }
+            final PackageParser.Package oldPackage =
+                    reconciledPackage.prepareResult.existingPackage;
+            final PackageParser.Package newPackage = reconciledPackage.pkgSetting.pkg;
+            if (reconciledPackage.prepareResult.system) {
+                // Re installation failed. Restore old information
+                // Remove new pkg information
+                if (newPackage != null) {
+                    removeInstalledPackageLI(newPackage, true);
+                }
+                // Add back the old system package
+                PackageParser.Package restoredPkg = null;
+                try {
+                    final List<ScanResult> restoreResults = scanPackageTracedLI(oldPackage,
+                            reconciledPackage.prepareResult.parseFlags, SCAN_UPDATE_SIGNATURE, 0,
+                            reconciledPackage.installForUser);
+                    commitSuccessfulScanResults(restoreResults);
+                    restoredPkg = restoreResults.get(0).pkgSetting.pkg;
+                } catch (PackageManagerException e) {
+                    Slog.e(TAG, "Failed to restore original package: " + e.getMessage());
+                }
+                synchronized (mPackages) {
+                    final boolean disabledSystem;
+                    // Remove existing system package
+                    removePackageLI(reconciledPackage.scanResult.pkgSetting.pkg, true);
+                    disabledSystem = disableSystemPackageLPw(
+                            reconciledPackage.scanResult.pkgSetting.pkg, restoredPkg);
+                    if (disabledSystem) {
+                        enableSystemPackageLPw(restoredPkg);
+                    }
+                    // Ensure the installer package name up to date
+                    setInstallerPackageNameLPw(reconciledPackage.scanResult.pkgSetting.pkg,
+                            reconciledPackage.installArgs.installerPackageName);
+                    // Update permissions for restored package
+                    mPermissionManager.updatePermissions(
+                            restoredPkg.packageName, restoredPkg, false, mPackages.values(),
+                            mPermissionCallback);
+                    mSettings.writeLPr();
+                }
+                Slog.i(TAG, "Successfully restored package : " + restoredPkg.packageName
+                        + " after failed upgrade");
+            } else if (reconciledPackage.prepareResult.replace) {
+                if (DEBUG_INSTALL) Slog.d(TAG, "Install failed, rolling pack: " + pkgName1);
+
+                // Revert all internal state mutations and added folders for the failed install
+                boolean deletedPkg = deletePackageLIF(pkgName1, null, true,
+                        allUsers, /*TODO: deleteFlags*/ 0,
+                        reconciledPackage.installResult.removedInfo, true, null);
+
+                // Restore the old package
+                if (deletedPkg) {
+                    if (DEBUG_INSTALL) Slog.d(TAG, "Install failed, reinstalling: " + oldPackage);
+                    File restoreFile = new File(oldPackage.codePath);
+                    // Parse old package
+                    boolean oldExternal = isExternal(oldPackage);
+                    int oldParseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
+                            | (oldPackage.isForwardLocked() ? PackageParser.PARSE_FORWARD_LOCK : 0)
+                            | (oldExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);
+                    int oldScanFlags = SCAN_UPDATE_SIGNATURE | SCAN_UPDATE_TIME;
+                    try {
+                        scanPackageTracedLI(restoreFile, oldParseFlags, oldScanFlags,
+                                /* origUpdateTime */ System.currentTimeMillis(), null);
+                    } catch (PackageManagerException e) {
+                        Slog.e(TAG, "Failed to restore package : " + pkgName1
+                                + " after failed upgrade: "
+                                + e.getMessage());
+                        return;
+                    }
+
+                    synchronized (mPackages) {
+                        // Ensure the installer package name up to date
+                        setInstallerPackageNameLPw(oldPackage,
+                                reconciledPackage.installArgs.installerPackageName);
+
+                        // Update permissions for restored package
+                        mPermissionManager.updatePermissions(
+                                oldPackage.packageName, oldPackage, false, mPackages.values(),
+                                mPermissionCallback);
+
+                        mSettings.writeLPr();
+                    }
+
+                    Slog.i(TAG, "Successfully restored package : " + pkgName1
+                            + " after failed upgrade");
+                }
+            } else {
+                // Remove package from internal structures, but keep around any
+                // data that might have already existed
+                deletePackageLIF(pkgName1, UserHandle.ALL, false, null,
+                        PackageManager.DELETE_KEEP_DATA,
+                        reconciledPackage.installResult.removedInfo, true, null);
+            }
+        }
+    }
+
+    /**
+     * The set of data needed to successfully install the prepared package. This includes data that
+     * will be used to scan and reconcile the package.
+     */
+    private static class PrepareResult {
+        public final int installReason;
+        public final String volumeUuid;
+        public final String installerPackageName;
+        public final UserHandle user;
+        public final boolean replace;
+        public final int scanFlags;
+        public final int parseFlags;
+        @Nullable /* The original Package if it is being replaced, otherwise {@code null} */
+        public final PackageParser.Package existingPackage;
+        public final PackageParser.Package packageToScan;
+        public final boolean clearCodeCache;
+        public final boolean system;
+        /* The original package name if it was changed during an update, otherwise {@code null}. */
+        @Nullable
+        public final String renamedPackage;
+        public final PackageFreezer freezer;
+
+        private PrepareResult(int installReason, String volumeUuid,
+                String installerPackageName, UserHandle user, boolean replace, int scanFlags,
+                int parseFlags, PackageParser.Package existingPackage,
+                PackageParser.Package packageToScan, boolean clearCodeCache, boolean system,
+                String renamedPackage,
+                PackageFreezer freezer) {
+            this.installReason = installReason;
+            this.volumeUuid = volumeUuid;
+            this.installerPackageName = installerPackageName;
+            this.user = user;
+            this.replace = replace;
+            this.scanFlags = scanFlags;
+            this.parseFlags = parseFlags;
+            this.existingPackage = existingPackage;
+            this.packageToScan = packageToScan;
+            this.clearCodeCache = clearCodeCache;
+            this.system = system;
+            this.renamedPackage = renamedPackage;
+            this.freezer = freezer;
+        }
+    }
+
+    private static class PrepareFailure extends PackageManagerException {
+
+        public String conflictingPackage;
+        public String conflictingPermission;
+
+        PrepareFailure(int error) {
+            super(error, "Failed to prepare for install.");
+        }
+
+        PrepareFailure(int error, String detailMessage) {
+            super(error, detailMessage);
+        }
+
+        PrepareFailure(String message, Exception e) {
+            super(e instanceof PackageParserException
+                    ? ((PackageParserException) e).error
+                    : ((PackageManagerException) e).error,
+                    ExceptionUtils.getCompleteMessage(message, e));
+        }
+
+        PrepareFailure conflictsWithExistingPermission(String conflictingPermission,
+                String conflictingPackage) {
+            this.conflictingPermission = conflictingPermission;
+            this.conflictingPackage = conflictingPackage;
+            return this;
+        }
+    }
+
     @GuardedBy("mInstallLock")
-    private void preparePackageLI(InstallArgs args, PackageInstalledInfo res) {
+    private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res)
+            throws PrepareFailure {
         final int installFlags = args.installFlags;
         final String installerPackageName = args.installerPackageName;
         final String volumeUuid = args.volumeUuid;
@@ -15492,7 +15587,6 @@
         final boolean forceSdk = ((installFlags & PackageManager.INSTALL_FORCE_SDK) != 0);
         final boolean virtualPreload =
                 ((installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
-        boolean replace = false;
         @ScanFlags int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
         if (args.move != null) {
             // moving a complete application; perform an initial scan on the new install location
@@ -15511,18 +15605,13 @@
             scanFlags |= SCAN_AS_VIRTUAL_PRELOAD;
         }
 
-        // Result object to be returned
-        res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
-        res.installerPackageName = installerPackageName;
-
         if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);
 
         // Sanity check
         if (instantApp && (forwardLocked || onExternal)) {
             Slog.i(TAG, "Incompatible ephemeral install; fwdLocked=" + forwardLocked
                     + " external=" + onExternal);
-            res.setReturnCode(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
-            return;
+            throw new PrepareFailure(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
         }
 
         // Retrieve PackageSettings and parse package
@@ -15531,6 +15620,7 @@
                 | (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)
                 | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0)
                 | (forceSdk ? PackageParser.PARSE_FORCE_SDK : 0);
+
         PackageParser pp = new PackageParser();
         pp.setSeparateProcesses(mSeparateProcesses);
         pp.setDisplayMetrics(mMetrics);
@@ -15542,8 +15632,7 @@
             pkg = pp.parsePackage(tmpPackageFile, parseFlags);
             DexMetadataHelper.validatePackageDexMetadata(pkg);
         } catch (PackageParserException e) {
-            res.setError("Failed parse during installPackageLI", e);
-            return;
+            throw new PrepareFailure("Failed parse during installPackageLI", e);
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
@@ -15553,16 +15642,14 @@
             if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) {
                 Slog.w(TAG,
                         "Instant app package " + pkg.packageName + " does not target at least O");
-                res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
+                throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
                         "Instant app package must target at least O");
-                return;
             }
             if (pkg.mSharedUserId != null) {
                 Slog.w(TAG, "Instant app package " + pkg.packageName
                         + " may not declare sharedUserId.");
-                res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
+                throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
                         "Instant app package may not declare a sharedUserId");
-                return;
             }
         }
 
@@ -15573,9 +15660,8 @@
             // No static shared libs on external storage
             if (onExternal) {
                 Slog.i(TAG, "Static shared libs can only be installed on internal storage.");
-                res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
+                throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
                         "Packages declaring static-shared libs cannot be updated");
-                return;
             }
         }
 
@@ -15614,10 +15700,9 @@
         }
 
         String pkgName = res.name = pkg.packageName;
-        if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
+        if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_TEST_ONLY) != 0) {
             if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) {
-                res.setError(INSTALL_FAILED_TEST_ONLY, "installPackageLI");
-                return;
+                throw new PrepareFailure(INSTALL_FAILED_TEST_ONLY, "installPackageLI");
             }
         }
 
@@ -15629,22 +15714,21 @@
                 PackageParser.collectCertificates(pkg, false /* skipVerify */);
             }
         } catch (PackageParserException e) {
-            res.setError("Failed collect during installPackageLI", e);
-            return;
+            throw new PrepareFailure("Failed collect during installPackageLI", e);
         }
 
         if (instantApp && pkg.mSigningDetails.signatureSchemeVersion
                 < SignatureSchemeVersion.SIGNING_BLOCK_V2) {
             Slog.w(TAG, "Instant app package " + pkg.packageName
                     + " is not signed with at least APK Signature Scheme v2");
-            res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
+            throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
                     "Instant app package must be signed with APK Signature Scheme v2 or greater");
-            return;
         }
 
         // Get rid of all references to package scan path via parser.
         pp = null;
         boolean systemApp = false;
+        boolean replace = false;
         synchronized (mPackages) {
             // Check if installing already existing package
             if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
@@ -15659,8 +15743,10 @@
                     pkg.setPackageName(oldName);
                     pkgName = pkg.packageName;
                     replace = true;
-                    if (DEBUG_INSTALL) Slog.d(TAG, "Replacing existing renamed package: oldName="
-                            + oldName + " pkgName=" + pkgName);
+                    if (DEBUG_INSTALL) {
+                        Slog.d(TAG, "Replacing existing renamed package: oldName="
+                                + oldName + " pkgName=" + pkgName);
+                    }
                 } else if (mPackages.containsKey(pkgName)) {
                     // This package, under its official name, already exists
                     // on the device; we should replace it.
@@ -15670,11 +15756,11 @@
 
                 // Child packages are installed through the parent package
                 if (pkg.parentPackage != null) {
-                    res.setError(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
+                    throw new PrepareFailure(
+                            PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
                             "Package " + pkg.packageName + " is child of package "
                                     + pkg.parentPackage.parentPackage + ". Child packages "
                                     + "can be updated only through the parent package.");
-                    return;
                 }
 
                 if (replace) {
@@ -15684,26 +15770,25 @@
                     final int newTargetSdk = pkg.applicationInfo.targetSdkVersion;
                     if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1
                             && newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) {
-                        res.setError(PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE,
+                        throw new PrepareFailure(
+                                PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE,
                                 "Package " + pkg.packageName + " new target SDK " + newTargetSdk
                                         + " doesn't support runtime permissions but the old"
                                         + " target SDK " + oldTargetSdk + " does.");
-                        return;
                     }
                     // Prevent persistent apps from being updated
                     if ((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0) {
-                        res.setError(PackageManager.INSTALL_FAILED_INVALID_APK,
+                        throw new PrepareFailure(PackageManager.INSTALL_FAILED_INVALID_APK,
                                 "Package " + oldPackage.packageName + " is a persistent app. "
                                         + "Persistent apps are not updateable.");
-                        return;
                     }
                     // Prevent installing of child packages
                     if (oldPackage.parentPackage != null) {
-                        res.setError(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
+                        throw new PrepareFailure(
+                                PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
                                 "Package " + pkg.packageName + " is child of package "
                                         + oldPackage.parentPackage + ". Child packages "
                                         + "can be updated only through the parent package.");
-                        return;
                     }
                 }
             }
@@ -15730,10 +15815,9 @@
                 final KeySetManagerService ksms = mSettings.mKeySetManagerService;
                 if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
                     if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
-                        res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
+                        throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
                                 + pkg.packageName + " upgrade keys do not match the "
                                 + "previously installed version");
-                        return;
                     }
                 } else {
                     try {
@@ -15750,8 +15834,7 @@
                             }
                         }
                     } catch (PackageManagerException e) {
-                        res.setError(e.error, e.getMessage());
-                        return;
+                        throw new PrepareFailure(e.error, e.getMessage());
                     }
                 }
 
@@ -15762,8 +15845,9 @@
                 res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
             }
 
+
             int N = pkg.permissions.size();
-            for (int i = N-1; i >= 0; i--) {
+            for (int i = N - 1; i >= 0; i--) {
                 final PackageParser.Permission perm = pkg.permissions.get(i);
                 final BasePermission bp =
                         (BasePermission) mPermissionManager.getPermissionTEMP(perm.info.name);
@@ -15788,7 +15872,7 @@
                     final KeySetManagerService ksms = mSettings.mKeySetManagerService;
                     if (sourcePackageName.equals(pkg.packageName)
                             && (ksms.shouldCheckUpgradeKeySetLocked(
-                                    sourcePackageSetting, scanFlags))) {
+                            sourcePackageSetting, scanFlags))) {
                         sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, pkg);
                     } else {
 
@@ -15796,12 +15880,12 @@
                         // package's certificate has rotated from the current one, or if it is an
                         // older certificate with which the current is ok with sharing permissions
                         if (sourcePackageSetting.signatures.mSigningDetails.checkCapability(
-                                        pkg.mSigningDetails,
-                                        PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
+                                pkg.mSigningDetails,
+                                PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
                             sigsOk = true;
                         } else if (pkg.mSigningDetails.checkCapability(
-                                        sourcePackageSetting.signatures.mSigningDetails,
-                                        PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
+                                sourcePackageSetting.signatures.mSigningDetails,
+                                PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
 
                             // the scanned package checks out, has signing certificate rotation
                             // history, and is newer; bring it over
@@ -15816,12 +15900,13 @@
                         // install to proceed; we fail the install on all other permission
                         // redefinitions.
                         if (!sourcePackageName.equals("android")) {
-                            res.setError(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package "
-                                    + pkg.packageName + " attempting to redeclare permission "
-                                    + perm.info.name + " already owned by " + sourcePackageName);
-                            res.origPermission = perm.info.name;
-                            res.origPackage = sourcePackageName;
-                            return;
+                            throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package "
+                                    + pkg.packageName
+                                    + " attempting to redeclare permission "
+                                    + perm.info.name + " already owned by "
+                                    + sourcePackageName)
+                                    .conflictsWithExistingPermission(perm.info.name,
+                                            sourcePackageName);
                         } else {
                             Slog.w(TAG, "Package " + pkg.packageName
                                     + " attempting to redeclare system permission "
@@ -15850,14 +15935,12 @@
         if (systemApp) {
             if (onExternal) {
                 // Abort update; system app can't be replaced with app on sdcard
-                res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
+                throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
                         "Cannot install updates to system apps on sdcard");
-                return;
             } else if (instantApp) {
                 // Abort update; system app can't be replaced with an instant app
-                res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
+                throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
                         "Cannot update a system app with an instant app");
-                return;
             }
         }
 
@@ -15885,13 +15968,13 @@
 
             try {
                 String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
-                    args.abiOverride : pkg.cpuAbiOverride);
+                        args.abiOverride : pkg.cpuAbiOverride);
                 final boolean extractNativeLibs = !pkg.isLibrary();
                 derivePackageAbi(pkg, abiOverride, extractNativeLibs);
             } catch (PackageManagerException pme) {
                 Slog.e(TAG, "Error deriving application ABI", pme);
-                res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI");
-                return;
+                throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
+                        "Error deriving application ABI");
             }
 
             // Shared libraries for the package need to be updated.
@@ -15905,8 +15988,7 @@
         }
 
         if (!args.doRename(res.returnCode, pkg)) {
-            res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
-            return;
+            throw new PrepareFailure(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
         }
 
         if (PackageManagerServiceUtils.isApkVerityEnabled()) {
@@ -15920,7 +16002,6 @@
                     apkPath = pkg.baseCodePath;
                 }
             }
-
             if (apkPath != null) {
                 final VerityUtils.SetupResult result =
                         VerityUtils.generateApkVeritySetupData(apkPath);
@@ -15932,16 +16013,15 @@
                         mInstaller.installApkVerity(apkPath, fd, result.getContentSize());
                         mInstaller.assertFsverityRootHashMatches(apkPath, signedRootHash);
                     } catch (InstallerException | IOException | DigestException |
-                             NoSuchAlgorithmException e) {
-                        res.setError(INSTALL_FAILED_INTERNAL_ERROR,
+                            NoSuchAlgorithmException e) {
+                        throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
                                 "Failed to set up verity: " + e);
-                        return;
                     } finally {
                         IoUtils.closeQuietly(fd);
                     }
                 } else if (result.isFailed()) {
-                    res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Failed to generate verity");
-                    return;
+                    throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
+                            "Failed to generate verity");
                 } else {
                     // Do nothing if verity is skipped. Will fall back to full apk verification on
                     // reboot.
@@ -15956,109 +16036,293 @@
                 Slog.d(TAG, "Not verifying instant app install for app links: " + pkgName);
             }
         }
+        final PackageFreezer freezer =
+                freezePackageForInstall(pkgName, installFlags, "installPackageLI");
+        boolean shouldCloseFreezerBeforeReturn = true;
+        try {
+            final PackageParser.Package existingPackage;
+            String renamedPackage = null;
+            boolean clearCodeCache = false;
+            boolean sysPkg = false;
+            String targetVolumeUuid = volumeUuid;
+            int targetScanFlags = scanFlags;
+            int targetParseFlags = parseFlags;
 
-        try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,
-                "installPackageLI")) {
             if (replace) {
+                targetVolumeUuid = null;
                 if (pkg.applicationInfo.isStaticSharedLibrary()) {
                     // Static libs have a synthetic package name containing the version
                     // and cannot be updated as an update would get a new package name,
                     // unless this is the exact same version code which is useful for
                     // development.
                     PackageParser.Package existingPkg = mPackages.get(pkg.packageName);
-                    if (existingPkg != null &&
-                            existingPkg.getLongVersionCode() != pkg.getLongVersionCode()) {
-                        res.setError(INSTALL_FAILED_DUPLICATE_PACKAGE, "Packages declaring "
-                                + "static-shared libs cannot be updated");
-                        return;
+                    if (existingPkg != null
+                            && existingPkg.getLongVersionCode() != pkg.getLongVersionCode()) {
+                        throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PACKAGE,
+                                "Packages declaring "
+                                        + "static-shared libs cannot be updated");
                     }
                 }
-                replacePackageLIF(pkg, parseFlags, scanFlags, args.user,
-                        installerPackageName, res, args.installReason);
-            } else {
-                installNewPackageLIF(pkg, parseFlags, scanFlags,
-                        args.user, installerPackageName, volumeUuid, res, args.installReason);
-            }
-        }
 
-        // Prepare the application profiles for the new code paths.
-        // This needs to be done before invoking dexopt so that any install-time profile
-        // can be used for optimizations.
-        mArtManagerService.prepareAppProfiles(pkg, resolveUserIds(args.user.getIdentifier()));
+                final boolean isInstantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
 
-        // Check whether we need to dexopt the app.
-        //
-        // NOTE: it is IMPORTANT to call dexopt:
-        //   - after doRename which will sync the package data from PackageParser.Package and its
-        //     corresponding ApplicationInfo.
-        //   - after installNewPackageLIF or replacePackageLIF which will update result with the
-        //     uid of the application (pkg.applicationInfo.uid).
-        //     This update happens in place!
-        //
-        // We only need to dexopt if the package meets ALL of the following conditions:
-        //   1) it is not forward locked.
-        //   2) it is not on on an external ASEC container.
-        //   3) it is not an instant app or if it is then dexopt is enabled via gservices.
-        //   4) it is not debuggable.
-        //
-        // Note that we do not dexopt instant apps by default. dexopt can take some time to
-        // complete, so we skip this step during installation. Instead, we'll take extra time
-        // the first time the instant app starts. It's preferred to do it this way to provide
-        // continuous progress to the useur instead of mysteriously blocking somewhere in the
-        // middle of running an instant app. The default behaviour can be overridden
-        // via gservices.
-        final boolean performDexopt = (res.returnCode == PackageManager.INSTALL_SUCCEEDED)
-                && !forwardLocked
-                && !pkg.applicationInfo.isExternalAsec()
-                && (!instantApp || Global.getInt(mContext.getContentResolver(),
-                Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
-                && ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0);
+                final PackageParser.Package oldPackage;
+                final PackageSetting ps;
+                final String pkgName11 = pkg.packageName;
+                final int[] allUsers;
+                final int[] installedUsers;
 
-        if (performDexopt) {
-            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
-            // Do not run PackageDexOptimizer through the local performDexOpt
-            // method because `pkg` may not be in `mPackages` yet.
-            //
-            // Also, don't fail application installs if the dexopt step fails.
-            DexoptOptions dexoptOptions = new DexoptOptions(pkg.packageName,
-                    REASON_INSTALL,
-                    DexoptOptions.DEXOPT_BOOT_COMPLETE |
-                    DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE);
-            mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
-                    null /* instructionSets */,
-                    getOrCreateCompilerPackageStats(pkg),
-                    mDexManager.getPackageUseInfoOrDefault(pkg.packageName),
-                    dexoptOptions);
-            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-        }
+                synchronized (mPackages) {
+                    oldPackage = mPackages.get(pkgName11);
+                    existingPackage = oldPackage;
+                    if (DEBUG_INSTALL) {
+                        Slog.d(TAG,
+                                "replacePackageLI: new=" + pkg + ", old=" + oldPackage);
+                    }
 
-        // Notify BackgroundDexOptService that the package has been changed.
-        // If this is an update of a package which used to fail to compile,
-        // BackgroundDexOptService will remove it from its blacklist.
-        // TODO: Layering violation
-        BackgroundDexOptService.notifyPackageChanged(pkg.packageName);
+                    // don't allow upgrade to target a release SDK from a pre-release SDK
+                    final boolean oldTargetsPreRelease = oldPackage.applicationInfo.targetSdkVersion
+                            == Build.VERSION_CODES.CUR_DEVELOPMENT;
+                    final boolean newTargetsPreRelease = pkg.applicationInfo.targetSdkVersion
+                            == Build.VERSION_CODES.CUR_DEVELOPMENT;
+                    if (oldTargetsPreRelease
+                            && !newTargetsPreRelease
+                            && ((parseFlags & PackageParser.PARSE_FORCE_SDK) == 0)) {
+                        Slog.w(TAG, "Can't install package targeting released sdk");
+                        throw new PrepareFailure(
+                                PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE);
+                    }
 
-        synchronized (mPackages) {
-            final PackageSetting ps = mSettings.mPackages.get(pkgName);
-            if (ps != null) {
-                res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
-                ps.setUpdateAvailable(false /*updateAvailable*/);
-            }
+                    ps = mSettings.mPackages.get(pkgName11);
 
-            final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-            for (int i = 0; i < childCount; i++) {
-                PackageParser.Package childPkg = pkg.childPackages.get(i);
-                PackageInstalledInfo childRes = res.addedChildPackages.get(childPkg.packageName);
-                PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
-                if (childPs != null) {
-                    childRes.newUsers = childPs.queryInstalledUsers(
-                            sUserManager.getUserIds(), true);
+                    // verify signatures are valid
+                    final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+                    if (ksms.shouldCheckUpgradeKeySetLocked(ps, scanFlags)) {
+                        if (!ksms.checkUpgradeKeySetLocked(ps, pkg)) {
+                            throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
+                                    "New package not signed by keys specified by upgrade-keysets: "
+                                            + pkgName11);
+                        }
+                    } else {
+                        // default to original signature matching
+                        if (!pkg.mSigningDetails.checkCapability(oldPackage.mSigningDetails,
+                                SigningDetails.CertCapabilities.INSTALLED_DATA)
+                                && !oldPackage.mSigningDetails.checkCapability(
+                                pkg.mSigningDetails,
+                                SigningDetails.CertCapabilities.ROLLBACK)) {
+                            throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
+                                    "New package has a different signature: " + pkgName11);
+                        }
+                    }
+
+                    // don't allow a system upgrade unless the upgrade hash matches
+                    if (oldPackage.restrictUpdateHash != null && oldPackage.isSystem()) {
+                        final byte[] digestBytes;
+                        try {
+                            final MessageDigest digest = MessageDigest.getInstance("SHA-512");
+                            updateDigest(digest, new File(pkg.baseCodePath));
+                            if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
+                                for (String path : pkg.splitCodePaths) {
+                                    updateDigest(digest, new File(path));
+                                }
+                            }
+                            digestBytes = digest.digest();
+                        } catch (NoSuchAlgorithmException | IOException e) {
+                            throw new PrepareFailure(INSTALL_FAILED_INVALID_APK,
+                                    "Could not compute hash: " + pkgName11);
+                        }
+                        if (!Arrays.equals(oldPackage.restrictUpdateHash, digestBytes)) {
+                            throw new PrepareFailure(INSTALL_FAILED_INVALID_APK,
+                                    "New package fails restrict-update check: " + pkgName11);
+                        }
+                        // retain upgrade restriction
+                        pkg.restrictUpdateHash = oldPackage.restrictUpdateHash;
+                    }
+
+                    // Check for shared user id changes
+                    String invalidPackageName =
+                            getParentOrChildPackageChangedSharedUser(oldPackage, pkg);
+                    if (invalidPackageName != null) {
+                        throw new PrepareFailure(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
+                                "Package " + invalidPackageName + " tried to change user "
+                                        + oldPackage.mSharedUserId);
+                    }
+
+                    // check if the new package supports all of the abis which the old package
+                    // supports
+                    boolean oldPkgSupportMultiArch =
+                            oldPackage.applicationInfo.secondaryCpuAbi != null;
+                    boolean newPkgSupportMultiArch = pkg.applicationInfo.secondaryCpuAbi != null;
+                    if (isSystemApp(oldPackage) && oldPkgSupportMultiArch
+                            && !newPkgSupportMultiArch) {
+                        throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
+                                "Update to package " + pkgName11 + " doesn't support multi arch");
+                    }
+
+                    // In case of rollback, remember per-user/profile install state
+                    allUsers = sUserManager.getUserIds();
+                    installedUsers = ps.queryInstalledUsers(allUsers, true);
+
+
+                    // don't allow an upgrade from full to ephemeral
+                    if (isInstantApp) {
+                        if (args.user == null || args.user.getIdentifier() == UserHandle.USER_ALL) {
+                            for (int currentUser : allUsers) {
+                                if (!ps.getInstantApp(currentUser)) {
+                                    // can't downgrade from full to instant
+                                    Slog.w(TAG,
+                                            "Can't replace full app with instant app: " + pkgName11
+                                                    + " for user: " + currentUser);
+                                    throw new PrepareFailure(
+                                            PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
+                                }
+                            }
+                        } else if (!ps.getInstantApp(args.user.getIdentifier())) {
+                            // can't downgrade from full to instant
+                            Slog.w(TAG, "Can't replace full app with instant app: " + pkgName11
+                                    + " for user: " + args.user.getIdentifier());
+                            throw new PrepareFailure(
+                                    PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
+                        }
+                    }
+                }
+
+                // Update what is removed
+                res.removedInfo = new PackageRemovedInfo(this);
+                res.removedInfo.uid = oldPackage.applicationInfo.uid;
+                res.removedInfo.removedPackage = oldPackage.packageName;
+                res.removedInfo.installerPackageName = ps.installerPackageName;
+                res.removedInfo.isStaticSharedLib = pkg.staticSharedLibName != null;
+                res.removedInfo.isUpdate = true;
+                res.removedInfo.origUsers = installedUsers;
+                res.removedInfo.installReasons = new SparseArray<>(installedUsers.length);
+                for (int i = 0; i < installedUsers.length; i++) {
+                    final int userId = installedUsers[i];
+                    res.removedInfo.installReasons.put(userId, ps.getInstallReason(userId));
+                }
+
+                final int childCount = (oldPackage.childPackages != null)
+                        ? oldPackage.childPackages.size() : 0;
+                for (int i = 0; i < childCount; i++) {
+                    boolean childPackageUpdated = false;
+                    PackageParser.Package childPkg = oldPackage.childPackages.get(i);
+                    final PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
+                    if (res.addedChildPackages != null) {
+                        PackageInstalledInfo childRes = res.addedChildPackages.get(
+                                childPkg.packageName);
+                        if (childRes != null) {
+                            childRes.removedInfo.uid = childPkg.applicationInfo.uid;
+                            childRes.removedInfo.removedPackage = childPkg.packageName;
+                            if (childPs != null) {
+                                childRes.removedInfo.installerPackageName =
+                                        childPs.installerPackageName;
+                            }
+                            childRes.removedInfo.isUpdate = true;
+                            childRes.removedInfo.installReasons = res.removedInfo.installReasons;
+                            childPackageUpdated = true;
+                        }
+                    }
+                    if (!childPackageUpdated) {
+                        PackageRemovedInfo childRemovedRes = new PackageRemovedInfo(this);
+                        childRemovedRes.removedPackage = childPkg.packageName;
+                        if (childPs != null) {
+                            childRemovedRes.installerPackageName = childPs.installerPackageName;
+                        }
+                        childRemovedRes.isUpdate = false;
+                        childRemovedRes.dataRemoved = true;
+                        synchronized (mPackages) {
+                            if (childPs != null) {
+                                childRemovedRes.origUsers = childPs.queryInstalledUsers(allUsers,
+                                        true);
+                            }
+                        }
+                        if (res.removedInfo.removedChildPackages == null) {
+                            res.removedInfo.removedChildPackages = new ArrayMap<>();
+                        }
+                        res.removedInfo.removedChildPackages.put(childPkg.packageName,
+                                childRemovedRes);
+                    }
+                }
+
+                sysPkg = (isSystemApp(oldPackage));
+                if (sysPkg) {
+                    // Set the system/privileged/oem/vendor/product flags as needed
+                    final boolean privileged = isPrivilegedApp(oldPackage);
+                    final boolean oem = isOemApp(oldPackage);
+                    final boolean vendor = isVendorApp(oldPackage);
+                    final boolean product = isProductApp(oldPackage);
+                    final @ParseFlags int systemParseFlags = parseFlags;
+                    final @ScanFlags int systemScanFlags = scanFlags
+                            | SCAN_AS_SYSTEM
+                            | (privileged ? SCAN_AS_PRIVILEGED : 0)
+                            | (oem ? SCAN_AS_OEM : 0)
+                            | (vendor ? SCAN_AS_VENDOR : 0)
+                            | (product ? SCAN_AS_PRODUCT : 0);
+
+                    if (DEBUG_INSTALL) {
+                        Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg
+                                + ", old=" + oldPackage);
+                    }
+                    clearCodeCache = true;
+                    res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
+                    pkg.setApplicationInfoFlags(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP,
+                            ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
+                    targetParseFlags = systemParseFlags;
+                    targetScanFlags = systemScanFlags;
+                } else { // non system replace
+                    replace = true;
+                    if (DEBUG_INSTALL) {
+                        Slog.d(TAG,
+                                "replaceNonSystemPackageLI: new=" + pkg + ", old="
+                                        + oldPackage);
+                    }
+
+                    String pkgName1 = oldPackage.packageName;
+                    boolean deletedPkg = true;
+                    boolean addedPkg = false;
+                    boolean updatedSettings = false;
+
+                    final long origUpdateTime = (pkg.mExtras != null)
+                            ? ((PackageSetting) pkg.mExtras).lastUpdateTime : 0;
+
+                }
+            } else { // new package install
+                replace = false;
+                existingPackage = null;
+                // Remember this for later, in case we need to rollback this install
+                String pkgName1 = pkg.packageName;
+
+                if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
+
+                // TODO(patb): MOVE TO RECONCILE
+                synchronized (mPackages) {
+                    renamedPackage = mSettings.getRenamedPackageLPr(pkgName1);
+                    if (renamedPackage != null) {
+                        // A package with the same name is already installed, though
+                        // it has been renamed to an older name.  The package we
+                        // are trying to install should be installed as an update to
+                        // the existing one, but that has not been requested, so bail.
+                        throw new PrepareFailure(INSTALL_FAILED_ALREADY_EXISTS,
+                                "Attempt to re-install " + pkgName1
+                                        + " without first uninstalling package running as "
+                                        + renamedPackage);
+                    }
+                    if (mPackages.containsKey(pkgName1)) {
+                        // Don't allow installation over an existing package with the same name.
+                        throw new PrepareFailure(INSTALL_FAILED_ALREADY_EXISTS,
+                                "Attempt to re-install " + pkgName1
+                                        + " without first uninstalling.");
+                    }
                 }
             }
-
-            if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
-                updateSequenceNumberLP(ps, res.newUsers);
-                updateInstantAppInstallerLocked(pkgName);
+            // we're passing the freezer back to be closed in a later phase of install
+            shouldCloseFreezerBeforeReturn = false;
+            return new PrepareResult(args.installReason, targetVolumeUuid, installerPackageName,
+                    args.user, replace, targetScanFlags, targetParseFlags, existingPackage, pkg,
+                    clearCodeCache, sysPkg, renamedPackage, freezer);
+        } finally {
+            if (shouldCloseFreezerBeforeReturn) {
+                freezer.close();
             }
         }
     }
@@ -16868,7 +17132,7 @@
             }
         }
 
-        removePackageLI(ps, (flags & PackageManager.DELETE_CHATTY) != 0);
+        removePackageLI(ps.name, (flags & PackageManager.DELETE_CHATTY) != 0);
 
         if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
             final PackageParser.Package resolvedPkg;
@@ -20925,8 +21189,18 @@
         //
         // We also have to cover non system users because we do not call the usual install package
         // methods for them.
+        //
+        // NOTE: in order to speed up first boot time we only create the current profile and do not
+        // update the content of the reference profile. A system image should already be configured
+        // with the right profile keys and the profiles for the speed-profile prebuilds should
+        // already be copied. That's done in #performDexOptUpgrade.
+        //
+        // TODO(calin, mathieuc): We should use .dm files for prebuilds profiles instead of
+        // manually copying them in #performDexOptUpgrade. When we do that we should have a more
+        // granular check here and only update the existing profiles.
         if (mIsUpgrade || mFirstBoot || (userId != UserHandle.USER_SYSTEM)) {
-            mArtManagerService.prepareAppProfiles(pkg, userId);
+            mArtManagerService.prepareAppProfiles(pkg, userId,
+                /* updateReferenceProfileContent= */ false);
         }
 
         if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && ceDataInode != -1) {
@@ -21979,6 +22253,22 @@
         }
 
         @Override
+        public boolean isPlatformSigned(String packageName) {
+            PackageSetting packageSetting = mSettings.mPackages.get(packageName);
+            if (packageSetting == null) {
+                return false;
+            }
+            PackageParser.Package pkg = packageSetting.pkg;
+            if (pkg == null) {
+                // May happen if package in on a removable sd card
+                return false;
+            }
+            return pkg.mSigningDetails.hasAncestorOrSelf(mPlatformPackage.mSigningDetails)
+                    || mPlatformPackage.mSigningDetails.checkCapability(pkg.mSigningDetails,
+                    PackageParser.SigningDetails.CertCapabilities.PERMISSION);
+        }
+
+        @Override
         public boolean isDataRestoreSafe(byte[] restoringFromSigHash, String packageName) {
             SigningDetails sd = getSigningDetails(packageName);
             if (sd == null) {
@@ -22090,7 +22380,7 @@
         }
 
         @Override
-        public PackageParser.Package getDisabledPackage(String packageName) {
+        public PackageParser.Package getDisabledSystemPackage(String packageName) {
             synchronized (mPackages) {
                 final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName);
                 return (ps != null) ? ps.pkg : null;
@@ -22098,6 +22388,12 @@
         }
 
         @Override
+        public @Nullable String getDisabledSystemPackageName(@NonNull String packageName) {
+            PackageParser.Package pkg = getDisabledSystemPackage(packageName);
+            return pkg == null ? null : pkg.packageName;
+        }
+
+        @Override
         public String getKnownPackageName(int knownPackage, int userId) {
             switch(knownPackage) {
                 case PackageManagerInternal.PACKAGE_BROWSER:
@@ -22135,21 +22431,6 @@
         }
 
         @Override
-        public void setSmsAppPackagesProvider(PackagesProvider provider) {
-            mDefaultPermissionPolicy.setSmsAppPackagesProvider(provider);
-        }
-
-        @Override
-        public void setDialerAppPackagesProvider(PackagesProvider provider) {
-            mDefaultPermissionPolicy.setDialerAppPackagesProvider(provider);
-        }
-
-        @Override
-        public void setSimCallManagerPackagesProvider(PackagesProvider provider) {
-            mDefaultPermissionPolicy.setSimCallManagerPackagesProvider(provider);
-        }
-
-        @Override
         public void setUseOpenWifiAppPackagesProvider(PackagesProvider provider) {
             mDefaultPermissionPolicy.setUseOpenWifiAppPackagesProvider(provider);
         }
@@ -22160,22 +22441,10 @@
         }
 
         @Override
-        public void grantDefaultPermissionsToDefaultSmsApp(String packageName, int userId) {
-            mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultSmsApp(packageName, userId);
-        }
-
-        @Override
-        public void grantDefaultPermissionsToDefaultDialerApp(String packageName, int userId) {
+        public void onDefaultDialerAppChanged(String packageName, int userId) {
             synchronized (mPackages) {
                 mSettings.setDefaultDialerPackageNameLPw(packageName, userId);
             }
-            mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultDialerApp(packageName, userId);
-        }
-
-        @Override
-        public void grantDefaultPermissionsToDefaultSimCallManager(String packageName, int userId) {
-            mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultSimCallManager(
-                    packageName, userId);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 361416a..a9f1b5c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -2234,6 +2234,9 @@
                 case "--install-location":
                     sessionParams.installLocation = Integer.parseInt(getNextArg());
                     break;
+                case "--install-reason":
+                    sessionParams.installReason = Integer.parseInt(getNextArg());
+                    break;
                 case "--force-uuid":
                     sessionParams.installFlags |= PackageManager.INSTALL_FORCE_VOLUME_UUID;
                     sessionParams.volumeUuid = getNextArg();
@@ -2742,8 +2745,8 @@
         pw.println("");
         pw.println("  install [-lrtsfdg] [-i PACKAGE] [--user USER_ID|all|current]");
         pw.println("       [-p INHERIT_PACKAGE] [--install-location 0/1/2]");
-        pw.println("       [--originating-uri URI] [---referrer URI]");
-        pw.println("       [--abi ABI_NAME] [--force-sdk]");
+        pw.println("       [--install-reason 0/1/2/3/4] [--originating-uri URI]");
+        pw.println("       [--referrer URI] [--abi ABI_NAME] [--force-sdk]");
         pw.println("       [--preload] [--instantapp] [--full] [--dont-kill]");
         pw.println("       [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES] [PATH|-]");
         pw.println("    Install an application.  Must provide the apk data to install, either as a");
@@ -2768,14 +2771,17 @@
         pw.println("      --full: cause the app to be installed as a non-ephemeral full app");
         pw.println("      --install-location: force the install location:");
         pw.println("          0=auto, 1=internal only, 2=prefer external");
+        pw.println("      --install-reason: indicates why the app is being installed:");
+        pw.println("          0=unknown, 1=admin policy, 2=device restore,");
+        pw.println("          3=device setup, 4=user request");
         pw.println("      --force-uuid: force install on to disk volume with given UUID");
         pw.println("      --force-sdk: allow install even when existing app targets platform");
         pw.println("          codename but new one targets a final API level");
         pw.println("");
         pw.println("  install-create [-lrtsfdg] [-i PACKAGE] [--user USER_ID|all|current]");
         pw.println("       [-p INHERIT_PACKAGE] [--install-location 0/1/2]");
-        pw.println("       [--originating-uri URI] [---referrer URI]");
-        pw.println("       [--abi ABI_NAME] [--force-sdk]");
+        pw.println("       [--install-reason 0/1/2/3/4] [--originating-uri URI]");
+        pw.println("       [--referrer URI] [--abi ABI_NAME] [--force-sdk]");
         pw.println("       [--preload] [--instantapp] [--full] [--dont-kill]");
         pw.println("       [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES]");
         pw.println("    Like \"install\", but starts an install session.  Use \"install-write\"");
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 727fb15..b850613 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -207,4 +207,13 @@
         writeUsersInfoToProto(proto, PackageProto.USERS);
         proto.end(packageToken);
     }
+
+    /** Updates all fields in the current setting from another. */
+    public void updateFrom(PackageSetting other) {
+        super.updateFrom(other);
+        appId = other.appId;
+        pkg = other.pkg;
+        sharedUserId = other.sharedUserId;
+        sharedUser = other.sharedUser;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 138594c..fd6aceb 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -26,7 +26,6 @@
 import android.content.pm.PackageParser;
 import android.content.pm.PackageUserState;
 import android.content.pm.Signature;
-import android.os.BaseBundle;
 import android.os.PersistableBundle;
 import android.service.pm.PackageProto;
 import android.util.ArraySet;
@@ -109,7 +108,7 @@
 
     // Whether this package is currently stopped, thus can not be
     // started until explicitly launched by the user.
-    private final SparseArray<PackageUserState> userState = new SparseArray<PackageUserState>();
+    private final SparseArray<PackageUserState> mUserState = new SparseArray<>();
 
     /**
      * Non-persisted value. During an "upgrade without restart", we need the set
@@ -118,7 +117,7 @@
      * restart, this field will be cleared since the classloader would be created
      * using the full set of code paths when the package's process is started.
      */
-    Set<String> oldCodePaths;
+    Set<String> mOldCodePaths;
 
     /** Package name of the app that installed this package */
     String installerPackageName;
@@ -223,7 +222,7 @@
     /**
      * Makes a shallow copy of the given package settings.
      *
-     * NOTE: For some fields [such as keySetData, signatures, userState, verificationInfo, etc...],
+     * NOTE: For some fields [such as keySetData, signatures, mUserState, verificationInfo, etc...],
      * the original object is copied and a new one is not created.
      */
     public void copyFrom(PackageSettingBase orig) {
@@ -244,7 +243,7 @@
         keySetData = orig.keySetData;
         lastUpdateTime = orig.lastUpdateTime;
         legacyNativeLibraryPathString = orig.legacyNativeLibraryPathString;
-        // Intentionally skip oldCodePaths; it's not relevant for copies
+        // Intentionally skip mOldCodePaths; it's not relevant for copies
         parentPackageName = orig.parentPackageName;
         primaryCpuAbiString = orig.primaryCpuAbiString;
         resourcePath = orig.resourcePath;
@@ -253,9 +252,9 @@
         signatures = orig.signatures;
         timeStamp = orig.timeStamp;
         uidError = orig.uidError;
-        userState.clear();
-        for (int i=0; i<orig.userState.size(); i++) {
-            userState.put(orig.userState.keyAt(i), orig.userState.valueAt(i));
+        mUserState.clear();
+        for (int i = 0; i < orig.mUserState.size(); i++) {
+            mUserState.put(orig.mUserState.keyAt(i), orig.mUserState.valueAt(i));
         }
         verificationInfo = orig.verificationInfo;
         versionCode = orig.versionCode;
@@ -271,16 +270,16 @@
     }
 
     private PackageUserState modifyUserState(int userId) {
-        PackageUserState state = userState.get(userId);
+        PackageUserState state = mUserState.get(userId);
         if (state == null) {
             state = new PackageUserState();
-            userState.put(userId, state);
+            mUserState.put(userId, state);
         }
         return state;
     }
 
     public PackageUserState readUserState(int userId) {
-        PackageUserState state = userState.get(userId);
+        PackageUserState state = mUserState.get(userId);
         if (state == null) {
             return DEFAULT_USER_STATE;
         }
@@ -330,7 +329,7 @@
     /** Only use for testing. Do NOT use in production code. */
     @VisibleForTesting
     SparseArray<PackageUserState> getUserState() {
-        return userState;
+        return mUserState;
     }
 
     boolean isAnyInstalled(int[] users) {
@@ -536,14 +535,14 @@
     }
 
     void removeUser(int userId) {
-        userState.delete(userId);
+        mUserState.delete(userId);
     }
 
     public int[] getNotInstalledUserIds() {
         int count = 0;
-        int userStateCount = userState.size();
+        int userStateCount = mUserState.size();
         for (int i = 0; i < userStateCount; i++) {
-            if (userState.valueAt(i).installed == false) {
+            if (!mUserState.valueAt(i).installed) {
                 count++;
             }
         }
@@ -551,8 +550,8 @@
         int[] excludedUserIds = new int[count];
         int idx = 0;
         for (int i = 0; i < userStateCount; i++) {
-            if (userState.valueAt(i).installed == false) {
-                excludedUserIds[idx++] = userState.keyAt(i);
+            if (!mUserState.valueAt(i).installed) {
+                excludedUserIds[idx++] = mUserState.keyAt(i);
             }
         }
         return excludedUserIds;
@@ -591,11 +590,11 @@
     }
 
     protected void writeUsersInfoToProto(ProtoOutputStream proto, long fieldId) {
-        int count = userState.size();
+        int count = mUserState.size();
         for (int i = 0; i < count; i++) {
             final long userToken = proto.start(fieldId);
-            final int userId = userState.keyAt(i);
-            final PackageUserState state = userState.valueAt(i);
+            final int userId = mUserState.keyAt(i);
+            final PackageUserState state = mUserState.valueAt(i);
             proto.write(PackageProto.UserInfoProto.ID, userId);
             final int installType;
             if (state.instantApp) {
@@ -630,4 +629,48 @@
         PackageUserState userState = readUserState(userId);
         return userState.harmfulAppWarning;
     }
+
+    protected PackageSettingBase updateFrom(PackageSettingBase other) {
+        super.copyFrom(other);
+        this.parentPackageName = other.parentPackageName;
+        this.childPackageNames = other.childPackageNames;
+        this.codePath = other.codePath;
+        this.codePathString = other.codePathString;
+        this.resourcePath = other.resourcePath;
+        this.resourcePathString = other.resourcePathString;
+        this.usesStaticLibraries = other.usesStaticLibraries;
+        this.usesStaticLibrariesVersions = other.usesStaticLibrariesVersions;
+        this.legacyNativeLibraryPathString = other.legacyNativeLibraryPathString;
+        this.primaryCpuAbiString = other.primaryCpuAbiString;
+        this.secondaryCpuAbiString = other.secondaryCpuAbiString;
+        this.cpuAbiOverrideString = other.cpuAbiOverrideString;
+        this.timeStamp = other.timeStamp;
+        this.firstInstallTime = other.firstInstallTime;
+        this.lastUpdateTime = other.lastUpdateTime;
+        this.versionCode = other.versionCode;
+        this.uidError = other.uidError;
+        this.signatures = other.signatures;
+        this.installPermissionsFixed = other.installPermissionsFixed;
+        this.keySetData = other.keySetData;
+        this.installerPackageName = other.installerPackageName;
+        this.isOrphaned = other.isOrphaned;
+        this.volumeUuid = other.volumeUuid;
+        this.categoryHint = other.categoryHint;
+        this.updateAvailable = other.updateAvailable;
+        this.verificationInfo = other.verificationInfo;
+
+        if (mOldCodePaths != null) {
+            if (other.mOldCodePaths != null) {
+                mOldCodePaths.clear();
+                mOldCodePaths.addAll(other.mOldCodePaths);
+            } else {
+                mOldCodePaths = null;
+            }
+        }
+        mUserState.clear();
+        for (int i = 0; i < other.mUserState.size(); i++) {
+            mUserState.put(other.mUserState.keyAt(i), other.mUserState.valueAt(i));
+        }
+        return this;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 6d242f4..5c88e06 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -539,16 +539,18 @@
             if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
                 p.pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
             }
-            mDisabledSysPackages.put(name, p);
-
+            final PackageSetting disabled;
             if (replaced) {
                 // a little trick...  when we install the new package, we don't
                 // want to modify the existing PackageSetting for the built-in
-                // version.  so at this point we need a new PackageSetting that
-                // is okay to muck with.
-                PackageSetting newp = new PackageSetting(p);
-                replacePackageLPw(name, newp);
+                // version.  so at this point we make a copy to place into the
+                // disabled set.
+                disabled = new PackageSetting(p);
+            } else {
+                disabled = p;
             }
+            mDisabledSysPackages.put(name, disabled);
+
             return true;
         }
         return false;
@@ -1105,19 +1107,6 @@
         mInstallerPackages.remove(packageName);
     }
 
-    private void replacePackageLPw(String name, PackageSetting newp) {
-        final PackageSetting p = mPackages.get(name);
-        if (p != null) {
-            if (p.sharedUser != null) {
-                p.sharedUser.removePackage(p);
-                p.sharedUser.addPackage(newp);
-            } else {
-                replaceUserIdLPw(p.appId, newp);
-            }
-        }
-        mPackages.put(name, newp);
-    }
-
     private boolean addUserIdLPw(int uid, Object obj, Object name) {
         if (uid > Process.LAST_APPLICATION_UID) {
             return false;
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index c94d209..1a8b2af 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -24,7 +24,6 @@
 import android.util.proto.ProtoOutputStream;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
 
 /**
@@ -69,24 +68,26 @@
         proto.end(token);
     }
 
-    void removePackage(PackageSetting packageSetting) {
-        if (packages.remove(packageSetting)) {
-            // recalculate the pkgFlags for this shared user if needed
-            if ((this.pkgFlags & packageSetting.pkgFlags) != 0) {
-                int aggregatedFlags = uidFlags;
-                for (PackageSetting ps : packages) {
-                    aggregatedFlags |= ps.pkgFlags;
-                }
-                setFlags(aggregatedFlags);
-            }
-            if ((this.pkgPrivateFlags & packageSetting.pkgPrivateFlags) != 0) {
-                int aggregatedPrivateFlags = uidPrivateFlags;
-                for (PackageSetting ps : packages) {
-                    aggregatedPrivateFlags |= ps.pkgPrivateFlags;
-                }
-                setPrivateFlags(aggregatedPrivateFlags);
-            }
+    boolean removePackage(PackageSetting packageSetting) {
+        if (!packages.remove(packageSetting)) {
+            return false;
         }
+        // recalculate the pkgFlags for this shared user if needed
+        if ((this.pkgFlags & packageSetting.pkgFlags) != 0) {
+            int aggregatedFlags = uidFlags;
+            for (PackageSetting ps : packages) {
+                aggregatedFlags |= ps.pkgFlags;
+            }
+            setFlags(aggregatedFlags);
+        }
+        if ((this.pkgPrivateFlags & packageSetting.pkgPrivateFlags) != 0) {
+            int aggregatedPrivateFlags = uidPrivateFlags;
+            for (PackageSetting ps : packages) {
+                aggregatedPrivateFlags |= ps.pkgPrivateFlags;
+            }
+            setPrivateFlags(aggregatedPrivateFlags);
+        }
+        return true;
     }
 
     void addPackage(PackageSetting packageSetting) {
@@ -143,4 +144,16 @@
         }
     }
 
+    /** Updates all fields in this shared user setting from another. */
+    public SharedUserSetting updateFrom(SharedUserSetting sharedUser) {
+        copyFrom(sharedUser);
+        this.userId = sharedUser.userId;
+        this.uidFlags = sharedUser.uidFlags;
+        this.uidPrivateFlags = sharedUser.uidPrivateFlags;
+        this.seInfoTargetSdkVersion = sharedUser.seInfoTargetSdkVersion;
+        this.packages.clear();
+        this.packages.addAll(sharedUser.packages);
+        this.signaturesChanged = sharedUser.signaturesChanged;
+        return this;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index 21daa39..910ea73 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -389,7 +389,8 @@
      *   - create the current primary profile to save time at app startup time.
      *   - copy the profiles from the associated dex metadata file to the reference profile.
      */
-    public void prepareAppProfiles(PackageParser.Package pkg, @UserIdInt int user) {
+    public void prepareAppProfiles(PackageParser.Package pkg, @UserIdInt int user,
+            boolean updateReferenceProfileContent) {
         final int appId = UserHandle.getAppId(pkg.applicationInfo.uid);
         if (user < 0) {
             Slog.wtf(TAG, "Invalid user id: " + user);
@@ -404,8 +405,14 @@
             for (int i = codePathsProfileNames.size() - 1; i >= 0; i--) {
                 String codePath = codePathsProfileNames.keyAt(i);
                 String profileName = codePathsProfileNames.valueAt(i);
-                File dexMetadata = DexMetadataHelper.findDexMetadataForFile(new File(codePath));
-                String dexMetadataPath = dexMetadata == null ? null : dexMetadata.getAbsolutePath();
+                String dexMetadataPath = null;
+                // Passing the dex metadata file to the prepare method will update the reference
+                // profile content. As such, we look for the dex metadata file only if we need to
+                // perform an update.
+                if (updateReferenceProfileContent) {
+                    File dexMetadata = DexMetadataHelper.findDexMetadataForFile(new File(codePath));
+                    dexMetadataPath = dexMetadata == null ? null : dexMetadata.getAbsolutePath();
+                }
                 synchronized (mInstaller) {
                     boolean result = mInstaller.prepareAppProfile(pkg.packageName, user, appId,
                             profileName, codePath, dexMetadataPath);
@@ -423,9 +430,10 @@
     /**
      * Prepares the app profiles for a set of users. {@see ArtManagerService#prepareAppProfiles}.
      */
-    public void prepareAppProfiles(PackageParser.Package pkg, int[] user) {
+    public void prepareAppProfiles(PackageParser.Package pkg, int[] user,
+            boolean updateReferenceProfileContent) {
         for (int i = 0; i < user.length; i++) {
-            prepareAppProfiles(pkg, user[i]);
+            prepareAppProfiles(pkg, user[i], updateReferenceProfileContent);
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
index e3e1590..602ce3b 100644
--- a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
+++ b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
@@ -93,7 +93,7 @@
     @GuardedBy("mPackageUseInfoMap")
     private final Map<String, PackageUseInfo> mPackageUseInfoMap;
 
-    public PackageDexUsage() {
+    /* package */ PackageDexUsage() {
         super("package-dex-usage.list", "PackageDexUsage_DiskWriter", /*lock*/ false);
         mPackageUseInfoMap = new HashMap<>();
     }
@@ -116,7 +116,7 @@
      * @return true if the dex load constitutes new information, or false if this information
      *         has been seen before.
      */
-    public boolean record(String owningPackageName, String dexPath, int ownerUserId,
+    /* package */ boolean record(String owningPackageName, String dexPath, int ownerUserId,
             String loaderIsa, boolean isUsedByOtherApps, boolean primaryOrSplit,
             String loadingPackageName, String classLoaderContext) {
         if (!PackageManagerServiceUtils.checkISA(loaderIsa)) {
@@ -193,7 +193,7 @@
      * Convenience method for sync reads which does not force the user to pass a useless
      * (Void) null.
      */
-    public void read() {
+    /* package */ void read() {
       read((Void) null);
     }
 
@@ -558,7 +558,7 @@
      * Remove the usage data associated with package {@code packageName}.
      * @return true if the package usage was found and removed successfully.
      */
-    public boolean removePackage(String packageName) {
+    /* package */ boolean removePackage(String packageName) {
         synchronized (mPackageUseInfoMap) {
             return mPackageUseInfoMap.remove(packageName) != null;
         }
@@ -653,11 +653,12 @@
         return packages;
     }
 
-    public void clear() {
+    /* package */ void clear() {
         synchronized (mPackageUseInfoMap) {
             mPackageUseInfoMap.clear();
         }
     }
+
     // Creates a deep copy of the class' mPackageUseInfoMap.
     private Map<String, PackageUseInfo> clonePackageUseInfoMap() {
         Map<String, PackageUseInfo> clone = new HashMap<>();
@@ -679,7 +680,7 @@
         throw new IllegalArgumentException("Unknown bool encoding: " + bool);
     }
 
-    public String dump() {
+    /* package */ String dump() {
         StringWriter sw = new StringWriter();
         write(sw);
         return sw.toString();
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 846c7b7..6f644dd 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -23,17 +23,17 @@
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.DownloadManager;
+import android.app.SearchManager;
 import android.app.admin.DevicePolicyManager;
 import android.companion.CompanionDeviceManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageList;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageManagerInternal.PackagesProvider;
 import android.content.pm.PackageManagerInternal.SyncAdapterPackagesProvider;
-import android.content.pm.PackageParser;
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.media.RingtoneManager;
@@ -47,12 +47,14 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
+import android.permission.PermissionManager;
 import android.print.PrintManager;
 import android.provider.CalendarContract;
 import android.provider.ContactsContract;
 import android.provider.MediaStore;
 import android.provider.Telephony.Sms.Intents;
 import android.security.Credentials;
+import android.speech.RecognitionService;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -61,6 +63,7 @@
 import android.util.Slog;
 import android.util.Xml;
 
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.XmlUtils;
 import com.android.server.LocalServices;
 
@@ -73,6 +76,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -94,10 +98,15 @@
     private static final String TAG = "DefaultPermGrantPolicy"; // must be <= 23 chars
     private static final boolean DEBUG = false;
 
-    private static final int DEFAULT_FLAGS =
+    @PackageManager.ResolveInfoFlags
+    private static final int DEFAULT_INTENT_QUERY_FLAGS =
             PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
                     | PackageManager.MATCH_UNINSTALLED_PACKAGES;
 
+    @PackageManager.PackageInfoFlags
+    private static final int DEFAULT_PACKAGE_INFO_QUERY_FLAGS =
+            PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_PERMISSIONS;
+
     private static final String AUDIO_MIME_TYPE = "audio/mpeg";
 
     private static final String TAG_EXCEPTIONS = "exceptions";
@@ -108,6 +117,8 @@
     private static final String ATTR_FIXED = "fixed";
 
     private static final Set<String> PHONE_PERMISSIONS = new ArraySet<>();
+
+
     static {
         PHONE_PERMISSIONS.add(Manifest.permission.READ_PHONE_STATE);
         PHONE_PERMISSIONS.add(Manifest.permission.CALL_PHONE);
@@ -219,7 +230,7 @@
     private final DefaultPermissionGrantedCallback mPermissionGrantedCallback;
     public interface DefaultPermissionGrantedCallback {
         /** Callback when permissions have been granted */
-        public void onDefaultRuntimePermissionsGranted(int userId);
+        void onDefaultRuntimePermissionsGranted(int userId);
     }
 
     public DefaultPermissionGrantPolicy(Context context, Looper looper,
@@ -291,9 +302,9 @@
         grantDefaultPermissionExceptions(userId);
     }
 
-    private void grantRuntimePermissionsForPackage(int userId, PackageParser.Package pkg) {
+    private void grantRuntimePermissionsForSystemPackage(int userId, PackageInfo pkg) {
         Set<String> permissions = new ArraySet<>();
-        for (String permission :  pkg.requestedPermissions) {
+        for (String permission : pkg.requestedPermissions) {
             final BasePermission bp = mPermissionManager.getPermission(permission);
             if (bp == null) {
                 continue;
@@ -307,36 +318,71 @@
         }
     }
 
-    private void grantAllRuntimePermissions(int userId) {
-        Log.i(TAG, "Granting all runtime permissions for user " + userId);
-        final PackageList packageList = mServiceInternal.getPackageList();
-        for (String packageName : packageList.getPackageNames()) {
-            final PackageParser.Package pkg = mServiceInternal.getPackage(packageName);
-            if (pkg == null) {
-                continue;
-            }
-            grantRuntimePermissionsForPackage(userId, pkg);
-        }
-    }
-
     public void scheduleReadDefaultPermissionExceptions() {
         mHandler.sendEmptyMessage(MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS);
     }
 
     private void grantPermissionsToSysComponentsAndPrivApps(int userId) {
         Log.i(TAG, "Granting permissions to platform components for user " + userId);
-        final PackageList packageList = mServiceInternal.getPackageList();
-        for (String packageName : packageList.getPackageNames()) {
-            final PackageParser.Package pkg = mServiceInternal.getPackage(packageName);
+        List<PackageInfo> packages = mContext.getPackageManager().getInstalledPackagesAsUser(
+                DEFAULT_PACKAGE_INFO_QUERY_FLAGS, UserHandle.USER_SYSTEM);
+        for (PackageInfo pkg : packages) {
             if (pkg == null) {
                 continue;
             }
             if (!isSysComponentOrPersistentPlatformSignedPrivApp(pkg)
                     || !doesPackageSupportRuntimePermissions(pkg)
-                    || pkg.requestedPermissions.isEmpty()) {
+                    || ArrayUtils.isEmpty(pkg.requestedPermissions)) {
                 continue;
             }
-            grantRuntimePermissionsForPackage(userId, pkg);
+            grantRuntimePermissionsForSystemPackage(userId, pkg);
+        }
+    }
+
+    @SafeVarargs
+    private final void grantIgnoringSystemPackage(String packageName, int userId,
+            Set<String>... permissionGroups) {
+        grantPermissionsToSystemPackage(packageName, userId, false, true, permissionGroups);
+    }
+
+    @SafeVarargs
+    private final void grantSystemFixedPermissionsToSystemPackage(String packageName, int userId,
+            Set<String>... permissionGroups) {
+        grantPermissionsToSystemPackage(packageName, userId, true, false, permissionGroups);
+    }
+
+    @SafeVarargs
+    private final void grantPermissionsToSystemPackage(
+            String packageName, int userId, Set<String>... permissionGroups) {
+        grantPermissionsToSystemPackage(packageName, userId, false, false, permissionGroups);
+    }
+
+    @SafeVarargs
+    private final void grantPermissionsToSystemPackage(String packageName, int userId,
+            boolean systemFixed, boolean ignoreSystemPackage, Set<String>... permissionGroups) {
+        if (!ignoreSystemPackage && !isSystemPackage(packageName)) {
+            return;
+        }
+        grantRuntimePermissionsToPackage(getSystemPackageInfo(packageName),
+                userId, systemFixed, ignoreSystemPackage, permissionGroups);
+    }
+
+    @SafeVarargs
+    private final void grantRuntimePermissionsToPackage(String packageName, int userId,
+            boolean systemFixed, boolean ignoreSystemPackage, Set<String>... permissionGroups) {
+        grantRuntimePermissionsToPackage(getPackageInfo(packageName),
+                userId, systemFixed, ignoreSystemPackage, permissionGroups);
+    }
+
+    @SafeVarargs
+    private final void grantRuntimePermissionsToPackage(PackageInfo packageName, int userId,
+            boolean systemFixed, boolean ignoreSystemPackage, Set<String>... permissionGroups) {
+        if (packageName == null) return;
+        if (doesPackageSupportRuntimePermissions(packageName)) {
+            for (Set<String> permissionGroup : permissionGroups) {
+                grantRuntimePermissions(packageName, permissionGroup, systemFixed,
+                        ignoreSystemPackage, userId);
+            }
         }
     }
 
@@ -379,594 +425,373 @@
                 syncAdapterPackagesProvider.getPackages(CalendarContract.AUTHORITY, userId) : null;
 
         // Installer
-        final String installerPackageName = mServiceInternal.getKnownPackageName(
-                PackageManagerInternal.PACKAGE_INSTALLER, userId);
-        PackageParser.Package installerPackage = getSystemPackage(installerPackageName);
-        if (installerPackage != null
-                && doesPackageSupportRuntimePermissions(installerPackage)) {
-            grantRuntimePermissions(installerPackage, STORAGE_PERMISSIONS, true, userId);
-        }
+        grantSystemFixedPermissionsToSystemPackage(
+                getKnownPackage(PackageManagerInternal.PACKAGE_INSTALLER, userId),
+                userId, STORAGE_PERMISSIONS);
 
         // Verifier
-        final String verifierPackageName = mServiceInternal.getKnownPackageName(
-                PackageManagerInternal.PACKAGE_VERIFIER, userId);
-        PackageParser.Package verifierPackage = getSystemPackage(verifierPackageName);
-        if (verifierPackage != null
-                && doesPackageSupportRuntimePermissions(verifierPackage)) {
-            grantRuntimePermissions(verifierPackage, STORAGE_PERMISSIONS, true, userId);
-            grantRuntimePermissions(verifierPackage, PHONE_PERMISSIONS, false, userId);
-            grantRuntimePermissions(verifierPackage, SMS_PERMISSIONS, false, userId);
-        }
+        final String verifier = getKnownPackage(PackageManagerInternal.PACKAGE_VERIFIER, userId);
+        grantSystemFixedPermissionsToSystemPackage(verifier, userId, STORAGE_PERMISSIONS);
+        grantPermissionsToSystemPackage(verifier, userId, PHONE_PERMISSIONS, SMS_PERMISSIONS);
 
         // SetupWizard
-        final String setupWizardPackageName = mServiceInternal.getKnownPackageName(
-                PackageManagerInternal.PACKAGE_SETUP_WIZARD, userId);
-        PackageParser.Package setupPackage = getSystemPackage(setupWizardPackageName);
-        if (setupPackage != null
-                && doesPackageSupportRuntimePermissions(setupPackage)) {
-            grantRuntimePermissions(setupPackage, PHONE_PERMISSIONS, userId);
-            grantRuntimePermissions(setupPackage, CONTACTS_PERMISSIONS, userId);
-            grantRuntimePermissions(setupPackage, LOCATION_PERMISSIONS, userId);
-            grantRuntimePermissions(setupPackage, CAMERA_PERMISSIONS, userId);
-        }
+        grantPermissionsToSystemPackage(
+                getKnownPackage(PackageManagerInternal.PACKAGE_SETUP_WIZARD, userId), userId,
+                PHONE_PERMISSIONS, CONTACTS_PERMISSIONS, LOCATION_PERMISSIONS, CAMERA_PERMISSIONS);
 
         // Camera
-        Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
-        PackageParser.Package cameraPackage = getDefaultSystemHandlerActivityPackage(
-                cameraIntent, userId);
-        if (cameraPackage != null
-                && doesPackageSupportRuntimePermissions(cameraPackage)) {
-            grantRuntimePermissions(cameraPackage, CAMERA_PERMISSIONS, userId);
-            grantRuntimePermissions(cameraPackage, MICROPHONE_PERMISSIONS, userId);
-            grantRuntimePermissions(cameraPackage, STORAGE_PERMISSIONS, userId);
-        }
+        grantPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackage(MediaStore.ACTION_IMAGE_CAPTURE, userId),
+                userId, CAMERA_PERMISSIONS, MICROPHONE_PERMISSIONS, STORAGE_PERMISSIONS);
 
         // Media provider
-        PackageParser.Package mediaStorePackage = getDefaultProviderAuthorityPackage(
-                MediaStore.AUTHORITY, userId);
-        if (mediaStorePackage != null) {
-            grantRuntimePermissions(mediaStorePackage, STORAGE_PERMISSIONS, true, userId);
-            grantRuntimePermissions(mediaStorePackage, MEDIA_AURAL_PERMISSIONS, true, userId);
-            grantRuntimePermissions(mediaStorePackage, MEDIA_VISUAL_PERMISSIONS, true, userId);
-            grantRuntimePermissions(mediaStorePackage, PHONE_PERMISSIONS, true, userId);
-        }
+        grantSystemFixedPermissionsToSystemPackage(
+                getDefaultProviderAuthorityPackage(MediaStore.AUTHORITY, userId), userId,
+                STORAGE_PERMISSIONS, MEDIA_AURAL_PERMISSIONS, MEDIA_VISUAL_PERMISSIONS,
+                PHONE_PERMISSIONS);
 
         // Downloads provider
-        PackageParser.Package downloadsPackage = getDefaultProviderAuthorityPackage(
-                "downloads", userId);
-        if (downloadsPackage != null) {
-            grantRuntimePermissions(downloadsPackage, STORAGE_PERMISSIONS, true, userId);
-        }
+        grantSystemFixedPermissionsToSystemPackage(
+                getDefaultProviderAuthorityPackage("downloads", userId), userId,
+                STORAGE_PERMISSIONS);
 
         // Downloads UI
-        Intent downloadsUiIntent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS);
-        PackageParser.Package downloadsUiPackage = getDefaultSystemHandlerActivityPackage(
-                downloadsUiIntent, userId);
-        if (downloadsUiPackage != null
-                && doesPackageSupportRuntimePermissions(downloadsUiPackage)) {
-            grantRuntimePermissions(downloadsUiPackage, STORAGE_PERMISSIONS, true, userId);
-        }
+        grantSystemFixedPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackage(
+                        DownloadManager.ACTION_VIEW_DOWNLOADS, userId),
+                userId, STORAGE_PERMISSIONS);
 
         // Storage provider
-        PackageParser.Package storagePackage = getDefaultProviderAuthorityPackage(
-                "com.android.externalstorage.documents", userId);
-        if (storagePackage != null) {
-            grantRuntimePermissions(storagePackage, STORAGE_PERMISSIONS, true, userId);
-        }
+        grantSystemFixedPermissionsToSystemPackage(
+                getDefaultProviderAuthorityPackage("com.android.externalstorage.documents", userId),
+                userId, STORAGE_PERMISSIONS);
 
         // CertInstaller
-        Intent certInstallerIntent = new Intent(Credentials.INSTALL_ACTION);
-        PackageParser.Package certInstallerPackage = getDefaultSystemHandlerActivityPackage(
-                certInstallerIntent, userId);
-        if (certInstallerPackage != null
-                && doesPackageSupportRuntimePermissions(certInstallerPackage)) {
-            grantRuntimePermissions(certInstallerPackage, STORAGE_PERMISSIONS, true, userId);
-        }
+        grantSystemFixedPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackage(Credentials.INSTALL_ACTION, userId), userId,
+                STORAGE_PERMISSIONS);
 
         // Dialer
         if (dialerAppPackageNames == null) {
-            Intent dialerIntent = new Intent(Intent.ACTION_DIAL);
-            PackageParser.Package dialerPackage = getDefaultSystemHandlerActivityPackage(
-                    dialerIntent, userId);
-            if (dialerPackage != null) {
-                grantDefaultPermissionsToDefaultSystemDialerApp(dialerPackage, userId);
-            }
+            String dialerPackage =
+                    getDefaultSystemHandlerActivityPackage(Intent.ACTION_DIAL, userId);
+            grantDefaultPermissionsToDefaultSystemDialerApp(dialerPackage, userId);
         } else {
             for (String dialerAppPackageName : dialerAppPackageNames) {
-                PackageParser.Package dialerPackage = getSystemPackage(dialerAppPackageName);
-                if (dialerPackage != null) {
-                    grantDefaultPermissionsToDefaultSystemDialerApp(dialerPackage, userId);
-                }
+                grantDefaultPermissionsToDefaultSystemDialerApp(dialerAppPackageName, userId);
             }
         }
 
         // Sim call manager
         if (simCallManagerPackageNames != null) {
             for (String simCallManagerPackageName : simCallManagerPackageNames) {
-                PackageParser.Package simCallManagerPackage =
-                        getSystemPackage(simCallManagerPackageName);
-                if (simCallManagerPackage != null) {
-                    grantDefaultPermissionsToDefaultSimCallManager(simCallManagerPackage,
-                            userId);
-                }
+                grantDefaultPermissionsToDefaultSystemSimCallManager(
+                        simCallManagerPackageName, userId);
             }
         }
 
         // Use Open Wifi
         if (useOpenWifiAppPackageNames != null) {
             for (String useOpenWifiPackageName : useOpenWifiAppPackageNames) {
-                PackageParser.Package useOpenWifiPackage =
-                        getSystemPackage(useOpenWifiPackageName);
-                if (useOpenWifiPackage != null) {
-                    grantDefaultPermissionsToDefaultSystemUseOpenWifiApp(useOpenWifiPackage,
-                            userId);
-                }
+                grantDefaultPermissionsToDefaultSystemUseOpenWifiApp(
+                        useOpenWifiPackageName, userId);
             }
         }
 
         // SMS
         if (smsAppPackageNames == null) {
-            Intent smsIntent = new Intent(Intent.ACTION_MAIN);
-            smsIntent.addCategory(Intent.CATEGORY_APP_MESSAGING);
-            PackageParser.Package smsPackage = getDefaultSystemHandlerActivityPackage(
-                    smsIntent, userId);
-            if (smsPackage != null) {
-               grantDefaultPermissionsToDefaultSystemSmsApp(smsPackage, userId);
-            }
+            String smsPackage = getDefaultSystemHandlerActivityPackageForCategory(
+                    Intent.CATEGORY_APP_MESSAGING, userId);
+            grantDefaultPermissionsToDefaultSystemSmsApp(smsPackage, userId);
         } else {
-            for (String smsPackageName : smsAppPackageNames) {
-                PackageParser.Package smsPackage = getSystemPackage(smsPackageName);
-                if (smsPackage != null) {
-                    grantDefaultPermissionsToDefaultSystemSmsApp(smsPackage, userId);
-                }
+            for (String smsPackage : smsAppPackageNames) {
+                grantDefaultPermissionsToDefaultSystemSmsApp(smsPackage, userId);
             }
         }
 
         // Cell Broadcast Receiver
-        Intent cbrIntent = new Intent(Intents.SMS_CB_RECEIVED_ACTION);
-        PackageParser.Package cbrPackage =
-                getDefaultSystemHandlerActivityPackage(cbrIntent, userId);
-        if (cbrPackage != null && doesPackageSupportRuntimePermissions(cbrPackage)) {
-            grantRuntimePermissions(cbrPackage, SMS_PERMISSIONS, userId);
-        }
+        grantPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackage(Intents.SMS_CB_RECEIVED_ACTION, userId),
+                userId, SMS_PERMISSIONS);
 
         // Carrier Provisioning Service
-        Intent carrierProvIntent = new Intent(Intents.SMS_CARRIER_PROVISION_ACTION);
-        PackageParser.Package carrierProvPackage =
-                getDefaultSystemHandlerServicePackage(carrierProvIntent, userId);
-        if (carrierProvPackage != null
-                && doesPackageSupportRuntimePermissions(carrierProvPackage)) {
-            grantRuntimePermissions(carrierProvPackage, SMS_PERMISSIONS, false, userId);
-        }
+        grantPermissionsToSystemPackage(
+                getDefaultSystemHandlerServicePackage(Intents.SMS_CARRIER_PROVISION_ACTION, userId),
+                userId, SMS_PERMISSIONS);
 
         // Calendar
-        Intent calendarIntent = new Intent(Intent.ACTION_MAIN);
-        calendarIntent.addCategory(Intent.CATEGORY_APP_CALENDAR);
-        PackageParser.Package calendarPackage = getDefaultSystemHandlerActivityPackage(
-                calendarIntent, userId);
-        if (calendarPackage != null
-                && doesPackageSupportRuntimePermissions(calendarPackage)) {
-            grantRuntimePermissions(calendarPackage, CALENDAR_PERMISSIONS, userId);
-            grantRuntimePermissions(calendarPackage, CONTACTS_PERMISSIONS, userId);
-        }
+        grantPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackageForCategory(
+                        Intent.CATEGORY_APP_CALENDAR, userId),
+                userId, CALENDAR_PERMISSIONS, CONTACTS_PERMISSIONS);
 
         // Calendar provider
-        PackageParser.Package calendarProviderPackage = getDefaultProviderAuthorityPackage(
-                CalendarContract.AUTHORITY, userId);
-        if (calendarProviderPackage != null) {
-            grantRuntimePermissions(calendarProviderPackage, CONTACTS_PERMISSIONS, userId);
-            grantRuntimePermissions(calendarProviderPackage, CALENDAR_PERMISSIONS,
-                    true, userId);
-            grantRuntimePermissions(calendarProviderPackage, STORAGE_PERMISSIONS, userId);
-        }
+        String calendarProvider =
+                getDefaultProviderAuthorityPackage(CalendarContract.AUTHORITY, userId);
+        grantPermissionsToSystemPackage(calendarProvider, userId,
+                CONTACTS_PERMISSIONS, STORAGE_PERMISSIONS);
+        grantSystemFixedPermissionsToSystemPackage(calendarProvider, userId, CALENDAR_PERMISSIONS);
 
         // Calendar provider sync adapters
-        List<PackageParser.Package> calendarSyncAdapters = getHeadlessSyncAdapterPackages(
-                calendarSyncAdapterPackages, userId);
-        final int calendarSyncAdapterCount = calendarSyncAdapters.size();
-        for (int i = 0; i < calendarSyncAdapterCount; i++) {
-            PackageParser.Package calendarSyncAdapter = calendarSyncAdapters.get(i);
-            if (doesPackageSupportRuntimePermissions(calendarSyncAdapter)) {
-                grantRuntimePermissions(calendarSyncAdapter, CALENDAR_PERMISSIONS, userId);
-            }
-        }
+        grantPermissionToEachSystemPackage(
+                getHeadlessSyncAdapterPackages(calendarSyncAdapterPackages, userId),
+                userId, CALENDAR_PERMISSIONS);
 
         // Contacts
-        Intent contactsIntent = new Intent(Intent.ACTION_MAIN);
-        contactsIntent.addCategory(Intent.CATEGORY_APP_CONTACTS);
-        PackageParser.Package contactsPackage = getDefaultSystemHandlerActivityPackage(
-                contactsIntent, userId);
-        if (contactsPackage != null
-                && doesPackageSupportRuntimePermissions(contactsPackage)) {
-            grantRuntimePermissions(contactsPackage, CONTACTS_PERMISSIONS, userId);
-            grantRuntimePermissions(contactsPackage, PHONE_PERMISSIONS, userId);
-        }
+        grantPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackageForCategory(
+                        Intent.CATEGORY_APP_CONTACTS, userId),
+                userId, CONTACTS_PERMISSIONS, PHONE_PERMISSIONS);
 
         // Contacts provider sync adapters
-        List<PackageParser.Package> contactsSyncAdapters = getHeadlessSyncAdapterPackages(
-                contactsSyncAdapterPackages, userId);
-        final int contactsSyncAdapterCount = contactsSyncAdapters.size();
-        for (int i = 0; i < contactsSyncAdapterCount; i++) {
-            PackageParser.Package contactsSyncAdapter = contactsSyncAdapters.get(i);
-            if (doesPackageSupportRuntimePermissions(contactsSyncAdapter)) {
-                grantRuntimePermissions(contactsSyncAdapter, CONTACTS_PERMISSIONS, userId);
-            }
-        }
+        grantPermissionToEachSystemPackage(
+                getHeadlessSyncAdapterPackages(contactsSyncAdapterPackages, userId),
+                userId, CONTACTS_PERMISSIONS);
 
         // Contacts provider
-        PackageParser.Package contactsProviderPackage = getDefaultProviderAuthorityPackage(
-                ContactsContract.AUTHORITY, userId);
-        if (contactsProviderPackage != null) {
-            grantRuntimePermissions(contactsProviderPackage, CONTACTS_PERMISSIONS,
-                    true, userId);
-            grantRuntimePermissions(contactsProviderPackage, PHONE_PERMISSIONS,
-                    true, userId);
-            grantRuntimePermissions(contactsProviderPackage, STORAGE_PERMISSIONS, userId);
-        }
+        String contactsProviderPackage =
+                getDefaultProviderAuthorityPackage(ContactsContract.AUTHORITY, userId);
+        grantSystemFixedPermissionsToSystemPackage(contactsProviderPackage, userId,
+                CONTACTS_PERMISSIONS, PHONE_PERMISSIONS);
+        grantPermissionsToSystemPackage(contactsProviderPackage, userId, STORAGE_PERMISSIONS);
 
         // Device provisioning
-        Intent deviceProvisionIntent = new Intent(
-                DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE);
-        PackageParser.Package deviceProvisionPackage =
-                getDefaultSystemHandlerActivityPackage(deviceProvisionIntent, userId);
-        if (deviceProvisionPackage != null
-                && doesPackageSupportRuntimePermissions(deviceProvisionPackage)) {
-            grantRuntimePermissions(deviceProvisionPackage, CONTACTS_PERMISSIONS, userId);
-        }
+        grantPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackage(
+                        DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, userId),
+                userId, CONTACTS_PERMISSIONS);
 
         // Maps
-        Intent mapsIntent = new Intent(Intent.ACTION_MAIN);
-        mapsIntent.addCategory(Intent.CATEGORY_APP_MAPS);
-        PackageParser.Package mapsPackage = getDefaultSystemHandlerActivityPackage(
-                mapsIntent, userId);
-        if (mapsPackage != null
-                && doesPackageSupportRuntimePermissions(mapsPackage)) {
-            grantRuntimePermissions(mapsPackage, LOCATION_PERMISSIONS, userId);
-        }
+        grantPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackageForCategory(Intent.CATEGORY_APP_MAPS, userId),
+                userId, LOCATION_PERMISSIONS);
 
         // Gallery
-        Intent galleryIntent = new Intent(Intent.ACTION_MAIN);
-        galleryIntent.addCategory(Intent.CATEGORY_APP_GALLERY);
-        PackageParser.Package galleryPackage = getDefaultSystemHandlerActivityPackage(
-                galleryIntent, userId);
-        if (galleryPackage != null
-                && doesPackageSupportRuntimePermissions(galleryPackage)) {
-            grantRuntimePermissions(galleryPackage, STORAGE_PERMISSIONS, userId);
-            grantRuntimePermissions(galleryPackage, MEDIA_VISUAL_PERMISSIONS, userId);
-        }
+        grantPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackageForCategory(
+                        Intent.CATEGORY_APP_GALLERY, userId),
+                userId, STORAGE_PERMISSIONS, MEDIA_VISUAL_PERMISSIONS);
 
         // Email
-        Intent emailIntent = new Intent(Intent.ACTION_MAIN);
-        emailIntent.addCategory(Intent.CATEGORY_APP_EMAIL);
-        PackageParser.Package emailPackage = getDefaultSystemHandlerActivityPackage(
-                emailIntent, userId);
-        if (emailPackage != null
-                && doesPackageSupportRuntimePermissions(emailPackage)) {
-            grantRuntimePermissions(emailPackage, CONTACTS_PERMISSIONS, userId);
-            grantRuntimePermissions(emailPackage, CALENDAR_PERMISSIONS, userId);
-        }
+        grantPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackageForCategory(
+                        Intent.CATEGORY_APP_EMAIL, userId),
+                userId, CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS);
 
         // Browser
-        PackageParser.Package browserPackage = null;
-        String defaultBrowserPackage = mServiceInternal.getKnownPackageName(
-                PackageManagerInternal.PACKAGE_BROWSER, userId);
-        if (defaultBrowserPackage != null) {
-            browserPackage = getPackage(defaultBrowserPackage);
-        }
+        String browserPackage = getKnownPackage(PackageManagerInternal.PACKAGE_BROWSER, userId);
         if (browserPackage == null) {
-            Intent browserIntent = new Intent(Intent.ACTION_MAIN);
-            browserIntent.addCategory(Intent.CATEGORY_APP_BROWSER);
-            browserPackage = getDefaultSystemHandlerActivityPackage(
-                    browserIntent, userId);
+            browserPackage = getDefaultSystemHandlerActivityPackageForCategory(
+                    Intent.CATEGORY_APP_BROWSER, userId);
+            if (!isSystemPackage(browserPackage)) {
+                browserPackage = null;
+            }
         }
-        if (browserPackage != null
-                && doesPackageSupportRuntimePermissions(browserPackage)) {
-            grantRuntimePermissions(browserPackage, LOCATION_PERMISSIONS, userId);
-        }
+        grantRuntimePermissionsToPackage(browserPackage, userId,
+                false /* systemFixed */, false /* ignoreSystemPackage */,
+                LOCATION_PERMISSIONS);
 
         // Voice interaction
         if (voiceInteractPackageNames != null) {
             for (String voiceInteractPackageName : voiceInteractPackageNames) {
-                PackageParser.Package voiceInteractPackage = getSystemPackage(
-                        voiceInteractPackageName);
-                if (voiceInteractPackage != null
-                        && doesPackageSupportRuntimePermissions(voiceInteractPackage)) {
-                    grantRuntimePermissions(voiceInteractPackage,
-                            CONTACTS_PERMISSIONS, userId);
-                    grantRuntimePermissions(voiceInteractPackage,
-                            CALENDAR_PERMISSIONS, userId);
-                    grantRuntimePermissions(voiceInteractPackage,
-                            MICROPHONE_PERMISSIONS, userId);
-                    grantRuntimePermissions(voiceInteractPackage,
-                            PHONE_PERMISSIONS, userId);
-                    grantRuntimePermissions(voiceInteractPackage,
-                            SMS_PERMISSIONS, userId);
-                    grantRuntimePermissions(voiceInteractPackage,
-                            LOCATION_PERMISSIONS, userId);
-                }
+                grantPermissionsToSystemPackage(voiceInteractPackageName, userId,
+                        CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS, MICROPHONE_PERMISSIONS,
+                        PHONE_PERMISSIONS, SMS_PERMISSIONS, LOCATION_PERMISSIONS);
             }
         }
 
         if (ActivityManager.isLowRamDeviceStatic()) {
             // Allow voice search on low-ram devices
-            Intent globalSearchIntent = new Intent("android.search.action.GLOBAL_SEARCH");
-            PackageParser.Package globalSearchPickerPackage =
-                getDefaultSystemHandlerActivityPackage(globalSearchIntent, userId);
-
-            if (globalSearchPickerPackage != null
-                    && doesPackageSupportRuntimePermissions(globalSearchPickerPackage)) {
-                grantRuntimePermissions(globalSearchPickerPackage,
-                    MICROPHONE_PERMISSIONS, false, userId);
-                grantRuntimePermissions(globalSearchPickerPackage,
-                    LOCATION_PERMISSIONS, false, userId);
-            }
+            grantPermissionsToSystemPackage(
+                    getDefaultSystemHandlerActivityPackage(
+                            SearchManager.INTENT_ACTION_GLOBAL_SEARCH, userId),
+                    userId, MICROPHONE_PERMISSIONS, LOCATION_PERMISSIONS);
         }
 
         // Voice recognition
-        Intent voiceRecoIntent = new Intent("android.speech.RecognitionService");
-        voiceRecoIntent.addCategory(Intent.CATEGORY_DEFAULT);
-        PackageParser.Package voiceRecoPackage = getDefaultSystemHandlerServicePackage(
-                voiceRecoIntent, userId);
-        if (voiceRecoPackage != null
-                && doesPackageSupportRuntimePermissions(voiceRecoPackage)) {
-            grantRuntimePermissions(voiceRecoPackage, MICROPHONE_PERMISSIONS, userId);
-        }
+        Intent voiceRecoIntent = new Intent(RecognitionService.SERVICE_INTERFACE)
+                .addCategory(Intent.CATEGORY_DEFAULT);
+        grantPermissionsToSystemPackage(
+                getDefaultSystemHandlerServicePackage(voiceRecoIntent, userId), userId,
+                MICROPHONE_PERMISSIONS);
 
         // Location
         if (locationPackageNames != null) {
             for (String packageName : locationPackageNames) {
-                PackageParser.Package locationPackage = getSystemPackage(packageName);
-                if (locationPackage != null
-                        && doesPackageSupportRuntimePermissions(locationPackage)) {
-                    grantRuntimePermissions(locationPackage, CONTACTS_PERMISSIONS, userId);
-                    grantRuntimePermissions(locationPackage, CALENDAR_PERMISSIONS, userId);
-                    grantRuntimePermissions(locationPackage, MICROPHONE_PERMISSIONS, userId);
-                    grantRuntimePermissions(locationPackage, PHONE_PERMISSIONS, userId);
-                    grantRuntimePermissions(locationPackage, SMS_PERMISSIONS, userId);
-                    grantRuntimePermissions(locationPackage, LOCATION_PERMISSIONS,
-                            true, userId);
-                    grantRuntimePermissions(locationPackage, CAMERA_PERMISSIONS, userId);
-                    grantRuntimePermissions(locationPackage, SENSORS_PERMISSIONS, userId);
-                    grantRuntimePermissions(locationPackage, STORAGE_PERMISSIONS, userId);
-                }
+                grantPermissionsToSystemPackage(packageName, userId,
+                        CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS, MICROPHONE_PERMISSIONS,
+                        PHONE_PERMISSIONS, SMS_PERMISSIONS, CAMERA_PERMISSIONS,
+                        SENSORS_PERMISSIONS, STORAGE_PERMISSIONS);
+                grantSystemFixedPermissionsToSystemPackage(packageName, userId,
+                        LOCATION_PERMISSIONS);
             }
         }
 
         // Music
-        Intent musicIntent = new Intent(Intent.ACTION_VIEW);
-        musicIntent.addCategory(Intent.CATEGORY_DEFAULT);
-        musicIntent.setDataAndType(Uri.fromFile(new File("foo.mp3")),
-                AUDIO_MIME_TYPE);
-        PackageParser.Package musicPackage = getDefaultSystemHandlerActivityPackage(
-                musicIntent, userId);
-        if (musicPackage != null
-                && doesPackageSupportRuntimePermissions(musicPackage)) {
-            grantRuntimePermissions(musicPackage, STORAGE_PERMISSIONS, userId);
-            grantRuntimePermissions(musicPackage, MEDIA_AURAL_PERMISSIONS, userId);
-        }
+        Intent musicIntent = new Intent(Intent.ACTION_VIEW)
+                .addCategory(Intent.CATEGORY_DEFAULT)
+                .setDataAndType(Uri.fromFile(new File("foo.mp3")), AUDIO_MIME_TYPE);
+        grantPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackage(musicIntent, userId), userId,
+                STORAGE_PERMISSIONS, MEDIA_AURAL_PERMISSIONS);
 
         // Home
-        Intent homeIntent = new Intent(Intent.ACTION_MAIN);
-        homeIntent.addCategory(Intent.CATEGORY_HOME);
-        homeIntent.addCategory(Intent.CATEGORY_LAUNCHER_APP);
-        PackageParser.Package homePackage = getDefaultSystemHandlerActivityPackage(
-                homeIntent, userId);
-        if (homePackage != null
-                && doesPackageSupportRuntimePermissions(homePackage)) {
-            grantRuntimePermissions(homePackage, LOCATION_PERMISSIONS, false, userId);
-        }
+        Intent homeIntent = new Intent(Intent.ACTION_MAIN)
+                .addCategory(Intent.CATEGORY_HOME)
+                .addCategory(Intent.CATEGORY_LAUNCHER_APP);
+        grantPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackage(homeIntent, userId), userId,
+                LOCATION_PERMISSIONS);
 
         // Watches
         if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH, 0)) {
             // Home application on watches
-            Intent wearHomeIntent = new Intent(Intent.ACTION_MAIN);
-            wearHomeIntent.addCategory(Intent.CATEGORY_HOME_MAIN);
 
-            PackageParser.Package wearHomePackage = getDefaultSystemHandlerActivityPackage(
-                    wearHomeIntent, userId);
-
-            if (wearHomePackage != null
-                    && doesPackageSupportRuntimePermissions(wearHomePackage)) {
-                grantRuntimePermissions(wearHomePackage, CONTACTS_PERMISSIONS, false,
-                        userId);
-                grantRuntimePermissions(wearHomePackage, PHONE_PERMISSIONS, true, userId);
-                grantRuntimePermissions(wearHomePackage, MICROPHONE_PERMISSIONS, false,
-                        userId);
-                grantRuntimePermissions(wearHomePackage, LOCATION_PERMISSIONS, false,
-                        userId);
-            }
+            String wearPackage = getDefaultSystemHandlerActivityPackageForCategory(
+                    Intent.CATEGORY_HOME_MAIN, userId);
+            grantPermissionsToSystemPackage(wearPackage, userId,
+                    CONTACTS_PERMISSIONS, MICROPHONE_PERMISSIONS, LOCATION_PERMISSIONS);
+            grantSystemFixedPermissionsToSystemPackage(wearPackage, userId, PHONE_PERMISSIONS);
 
             // Fitness tracking on watches
-            Intent trackIntent = new Intent(ACTION_TRACK);
-            PackageParser.Package trackPackage = getDefaultSystemHandlerActivityPackage(
-                    trackIntent, userId);
-            if (trackPackage != null
-                    && doesPackageSupportRuntimePermissions(trackPackage)) {
-                grantRuntimePermissions(trackPackage, SENSORS_PERMISSIONS, false, userId);
-                grantRuntimePermissions(trackPackage, LOCATION_PERMISSIONS, false, userId);
-            }
+            grantPermissionsToSystemPackage(
+                    getDefaultSystemHandlerActivityPackage(ACTION_TRACK, userId), userId,
+                    SENSORS_PERMISSIONS, LOCATION_PERMISSIONS);
         }
 
         // Print Spooler
-        PackageParser.Package printSpoolerPackage = getSystemPackage(
-                PrintManager.PRINT_SPOOLER_PACKAGE_NAME);
-        if (printSpoolerPackage != null
-                && doesPackageSupportRuntimePermissions(printSpoolerPackage)) {
-            grantRuntimePermissions(printSpoolerPackage, LOCATION_PERMISSIONS, true, userId);
-        }
+        grantSystemFixedPermissionsToSystemPackage(PrintManager.PRINT_SPOOLER_PACKAGE_NAME, userId,
+                LOCATION_PERMISSIONS);
 
         // EmergencyInfo
-        Intent emergencyInfoIntent = new Intent(TelephonyManager.ACTION_EMERGENCY_ASSISTANCE);
-        PackageParser.Package emergencyInfoPckg = getDefaultSystemHandlerActivityPackage(
-                emergencyInfoIntent, userId);
-        if (emergencyInfoPckg != null
-                && doesPackageSupportRuntimePermissions(emergencyInfoPckg)) {
-            grantRuntimePermissions(emergencyInfoPckg, CONTACTS_PERMISSIONS, true, userId);
-            grantRuntimePermissions(emergencyInfoPckg, PHONE_PERMISSIONS, true, userId);
-        }
+        grantSystemFixedPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackage(
+                        TelephonyManager.ACTION_EMERGENCY_ASSISTANCE, userId),
+                userId, CONTACTS_PERMISSIONS, PHONE_PERMISSIONS);
 
         // NFC Tag viewer
-        Intent nfcTagIntent = new Intent(Intent.ACTION_VIEW);
-        nfcTagIntent.setType("vnd.android.cursor.item/ndef_msg");
-        PackageParser.Package nfcTagPkg = getDefaultSystemHandlerActivityPackage(
-                nfcTagIntent, userId);
-        if (nfcTagPkg != null
-                && doesPackageSupportRuntimePermissions(nfcTagPkg)) {
-            grantRuntimePermissions(nfcTagPkg, CONTACTS_PERMISSIONS, false, userId);
-            grantRuntimePermissions(nfcTagPkg, PHONE_PERMISSIONS, false, userId);
-        }
+        Intent nfcTagIntent = new Intent(Intent.ACTION_VIEW)
+                .setType("vnd.android.cursor.item/ndef_msg");
+        grantPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackage(nfcTagIntent, userId), userId,
+                CONTACTS_PERMISSIONS, PHONE_PERMISSIONS);
 
         // Storage Manager
-        Intent storageManagerIntent = new Intent(StorageManager.ACTION_MANAGE_STORAGE);
-        PackageParser.Package storageManagerPckg = getDefaultSystemHandlerActivityPackage(
-                storageManagerIntent, userId);
-        if (storageManagerPckg != null
-                && doesPackageSupportRuntimePermissions(storageManagerPckg)) {
-            grantRuntimePermissions(storageManagerPckg, STORAGE_PERMISSIONS, true, userId);
-        }
+        grantSystemFixedPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackage(
+                        StorageManager.ACTION_MANAGE_STORAGE, userId),
+                userId, STORAGE_PERMISSIONS);
 
         // Companion devices
-        PackageParser.Package companionDeviceDiscoveryPackage = getSystemPackage(
-                CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME);
-        if (companionDeviceDiscoveryPackage != null
-                && doesPackageSupportRuntimePermissions(companionDeviceDiscoveryPackage)) {
-            grantRuntimePermissions(companionDeviceDiscoveryPackage,
-                    LOCATION_PERMISSIONS, true, userId);
-        }
+        grantSystemFixedPermissionsToSystemPackage(
+                CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME, userId,
+                LOCATION_PERMISSIONS);
 
         // Ringtone Picker
-        Intent ringtonePickerIntent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
-        PackageParser.Package ringtonePickerPackage =
-                getDefaultSystemHandlerActivityPackage(ringtonePickerIntent, userId);
-        if (ringtonePickerPackage != null
-                && doesPackageSupportRuntimePermissions(ringtonePickerPackage)) {
-            grantRuntimePermissions(ringtonePickerPackage,
-                    STORAGE_PERMISSIONS, true, userId);
-        }
+        grantSystemFixedPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackage(
+                        RingtoneManager.ACTION_RINGTONE_PICKER, userId),
+                userId, STORAGE_PERMISSIONS);
 
         // TextClassifier Service
         String textClassifierPackageName =
                 mContext.getPackageManager().getSystemTextClassifierPackageName();
         if (!TextUtils.isEmpty(textClassifierPackageName)) {
-            PackageParser.Package textClassifierPackage =
-                    getSystemPackage(textClassifierPackageName);
-            if (textClassifierPackage != null
-                    && doesPackageSupportRuntimePermissions(textClassifierPackage)) {
-                grantRuntimePermissions(textClassifierPackage, PHONE_PERMISSIONS, false, userId);
-                grantRuntimePermissions(textClassifierPackage, SMS_PERMISSIONS, false, userId);
-                grantRuntimePermissions(textClassifierPackage, CALENDAR_PERMISSIONS, false, userId);
-                grantRuntimePermissions(textClassifierPackage, LOCATION_PERMISSIONS, false, userId);
-                grantRuntimePermissions(textClassifierPackage, CONTACTS_PERMISSIONS, false, userId);
-            }
+            grantPermissionsToSystemPackage(textClassifierPackageName, userId,
+                    PHONE_PERMISSIONS, SMS_PERMISSIONS, CALENDAR_PERMISSIONS,
+                    LOCATION_PERMISSIONS, CONTACTS_PERMISSIONS);
         }
 
         // There is no real "marker" interface to identify the shared storage backup, it is
         // hardcoded in BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE.
-        PackageParser.Package sharedStorageBackupPackage = getSystemPackage(
-                "com.android.sharedstoragebackup");
-        if (sharedStorageBackupPackage != null) {
-            grantRuntimePermissions(sharedStorageBackupPackage, STORAGE_PERMISSIONS, true, userId);
-        }
+        grantSystemFixedPermissionsToSystemPackage("com.android.sharedstoragebackup", userId,
+                STORAGE_PERMISSIONS);
 
         if (mPermissionGrantedCallback != null) {
             mPermissionGrantedCallback.onDefaultRuntimePermissionsGranted(userId);
         }
     }
 
-    private void grantDefaultPermissionsToDefaultSystemDialerApp(
-            PackageParser.Package dialerPackage, int userId) {
-        if (doesPackageSupportRuntimePermissions(dialerPackage)) {
-            boolean isPhonePermFixed =
-                    mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH, 0);
-            grantRuntimePermissions(
-                    dialerPackage, PHONE_PERMISSIONS, isPhonePermFixed, userId);
-            grantRuntimePermissions(dialerPackage, CONTACTS_PERMISSIONS, userId);
-            grantRuntimePermissions(dialerPackage, SMS_PERMISSIONS, userId);
-            grantRuntimePermissions(dialerPackage, MICROPHONE_PERMISSIONS, userId);
-            grantRuntimePermissions(dialerPackage, CAMERA_PERMISSIONS, userId);
+    private String getDefaultSystemHandlerActivityPackageForCategory(String category, int userId) {
+        return getDefaultSystemHandlerActivityPackage(
+                new Intent(Intent.ACTION_MAIN).addCategory(category), userId);
+    }
+
+    @SafeVarargs
+    private final void grantPermissionToEachSystemPackage(
+            ArrayList<String> packages, int userId, Set<String>... permissions) {
+        if (packages == null) return;
+        final int count = packages.size();
+        for (int i = 0; i < count; i++) {
+            grantPermissionsToSystemPackage(packages.get(i), userId, permissions);
         }
     }
 
-    private void grantDefaultPermissionsToDefaultSystemSmsApp(
-            PackageParser.Package smsPackage, int userId) {
-        if (doesPackageSupportRuntimePermissions(smsPackage)) {
-            grantRuntimePermissions(smsPackage, PHONE_PERMISSIONS, userId);
-            grantRuntimePermissions(smsPackage, CONTACTS_PERMISSIONS, userId);
-            grantRuntimePermissions(smsPackage, SMS_PERMISSIONS, userId);
-            grantRuntimePermissions(smsPackage, STORAGE_PERMISSIONS, userId);
-            grantRuntimePermissions(smsPackage, MICROPHONE_PERMISSIONS, userId);
-            grantRuntimePermissions(smsPackage, CAMERA_PERMISSIONS, userId);
+    private String getKnownPackage(int knownPkgId, int userId) {
+        return mServiceInternal.getKnownPackageName(knownPkgId, userId);
+    }
+
+    private void grantDefaultPermissionsToDefaultSystemDialerApp(
+            String dialerPackage, int userId) {
+        if (dialerPackage == null) {
+            return;
         }
+        boolean isPhonePermFixed =
+                mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH, 0);
+        if (isPhonePermFixed) {
+            grantSystemFixedPermissionsToSystemPackage(dialerPackage, userId, PHONE_PERMISSIONS);
+        } else {
+            grantPermissionsToSystemPackage(dialerPackage, userId, PHONE_PERMISSIONS);
+        }
+        grantPermissionsToSystemPackage(dialerPackage, userId,
+                CONTACTS_PERMISSIONS, SMS_PERMISSIONS, MICROPHONE_PERMISSIONS, CAMERA_PERMISSIONS);
+    }
+
+    private void grantDefaultPermissionsToDefaultSystemSmsApp(String smsPackage, int userId) {
+        grantPermissionsToSystemPackage(smsPackage, userId,
+                PHONE_PERMISSIONS, CONTACTS_PERMISSIONS, SMS_PERMISSIONS,
+                STORAGE_PERMISSIONS, MICROPHONE_PERMISSIONS, CAMERA_PERMISSIONS);
     }
 
     private void grantDefaultPermissionsToDefaultSystemUseOpenWifiApp(
-            PackageParser.Package useOpenWifiPackage, int userId) {
-        if (doesPackageSupportRuntimePermissions(useOpenWifiPackage)) {
-            grantRuntimePermissions(useOpenWifiPackage, COARSE_LOCATION_PERMISSIONS, userId);
-        }
+            String useOpenWifiPackage, int userId) {
+        grantPermissionsToSystemPackage(
+                useOpenWifiPackage, userId, COARSE_LOCATION_PERMISSIONS);
     }
 
     public void grantDefaultPermissionsToDefaultSmsApp(String packageName, int userId) {
         Log.i(TAG, "Granting permissions to default sms app for user:" + userId);
-        if (packageName == null) {
-            return;
-        }
-        PackageParser.Package smsPackage = getPackage(packageName);
-        if (smsPackage != null && doesPackageSupportRuntimePermissions(smsPackage)) {
-            grantRuntimePermissions(smsPackage, PHONE_PERMISSIONS, false, true, userId);
-            grantRuntimePermissions(smsPackage, CONTACTS_PERMISSIONS, false, true, userId);
-            grantRuntimePermissions(smsPackage, SMS_PERMISSIONS, false, true, userId);
-            grantRuntimePermissions(smsPackage, STORAGE_PERMISSIONS, false, true, userId);
-            grantRuntimePermissions(smsPackage, MICROPHONE_PERMISSIONS, false, true, userId);
-            grantRuntimePermissions(smsPackage, CAMERA_PERMISSIONS, false, true, userId);
-        }
+        grantIgnoringSystemPackage(packageName, userId,
+                PHONE_PERMISSIONS, CONTACTS_PERMISSIONS, SMS_PERMISSIONS, STORAGE_PERMISSIONS,
+                MICROPHONE_PERMISSIONS, CAMERA_PERMISSIONS);
     }
 
     public void grantDefaultPermissionsToDefaultDialerApp(String packageName, int userId) {
+        mServiceInternal.onDefaultDialerAppChanged(packageName, userId);
         Log.i(TAG, "Granting permissions to default dialer app for user:" + userId);
-        if (packageName == null) {
-            return;
-        }
-        PackageParser.Package dialerPackage = getPackage(packageName);
-        if (dialerPackage != null
-                && doesPackageSupportRuntimePermissions(dialerPackage)) {
-            grantRuntimePermissions(dialerPackage, PHONE_PERMISSIONS, false, true, userId);
-            grantRuntimePermissions(dialerPackage, CONTACTS_PERMISSIONS, false, true, userId);
-            grantRuntimePermissions(dialerPackage, SMS_PERMISSIONS, false, true, userId);
-            grantRuntimePermissions(dialerPackage, MICROPHONE_PERMISSIONS, false, true, userId);
-            grantRuntimePermissions(dialerPackage, CAMERA_PERMISSIONS, false, true, userId);
-        }
+        grantIgnoringSystemPackage(packageName, userId,
+                PHONE_PERMISSIONS, CONTACTS_PERMISSIONS, SMS_PERMISSIONS,
+                MICROPHONE_PERMISSIONS, CAMERA_PERMISSIONS);
     }
 
     public void grantDefaultPermissionsToDefaultUseOpenWifiApp(String packageName, int userId) {
         Log.i(TAG, "Granting permissions to default Use Open WiFi app for user:" + userId);
-        if (packageName == null) {
-            return;
-        }
-        PackageParser.Package useOpenWifiPackage = getPackage(packageName);
-        if (useOpenWifiPackage != null
-                && doesPackageSupportRuntimePermissions(useOpenWifiPackage)) {
-            grantRuntimePermissions(
-                    useOpenWifiPackage, COARSE_LOCATION_PERMISSIONS, false, true, userId);
-        }
-    }
-
-    private void grantDefaultPermissionsToDefaultSimCallManager(
-            PackageParser.Package simCallManagerPackage, int userId) {
-        Log.i(TAG, "Granting permissions to sim call manager for user:" + userId);
-        if (doesPackageSupportRuntimePermissions(simCallManagerPackage)) {
-            grantRuntimePermissions(simCallManagerPackage, PHONE_PERMISSIONS, userId);
-            grantRuntimePermissions(simCallManagerPackage, MICROPHONE_PERMISSIONS, userId);
-        }
+        grantIgnoringSystemPackage(packageName, userId, COARSE_LOCATION_PERMISSIONS);
     }
 
     public void grantDefaultPermissionsToDefaultSimCallManager(String packageName, int userId) {
         if (packageName == null) {
             return;
         }
-        PackageParser.Package simCallManagerPackage = getPackage(packageName);
-        if (simCallManagerPackage != null) {
-            grantDefaultPermissionsToDefaultSimCallManager(simCallManagerPackage, userId);
+        Log.i(TAG, "Granting permissions to sim call manager for user:" + userId);
+        grantRuntimePermissionsToPackage(packageName, userId, false, false,
+                PHONE_PERMISSIONS, MICROPHONE_PERMISSIONS);
+    }
+
+    private void grantDefaultPermissionsToDefaultSystemSimCallManager(
+            String packageName, int userId) {
+        if (isSystemPackage(packageName)) {
+            grantDefaultPermissionsToDefaultSimCallManager(packageName, userId);
         }
     }
 
@@ -976,13 +801,8 @@
             return;
         }
         for (String packageName : packageNames) {
-            PackageParser.Package carrierPackage = getSystemPackage(packageName);
-            if (carrierPackage != null
-                    && doesPackageSupportRuntimePermissions(carrierPackage)) {
-                grantRuntimePermissions(carrierPackage, PHONE_PERMISSIONS, userId);
-                grantRuntimePermissions(carrierPackage, LOCATION_PERMISSIONS, userId);
-                grantRuntimePermissions(carrierPackage, SMS_PERMISSIONS, userId);
-            }
+            grantPermissionsToSystemPackage(packageName, userId,
+                    PHONE_PERMISSIONS, LOCATION_PERMISSIONS, SMS_PERMISSIONS);
         }
     }
 
@@ -992,15 +812,9 @@
             return;
         }
         for (String packageName : packageNames) {
-            PackageParser.Package imsServicePackage = getSystemPackage(packageName);
-            if (imsServicePackage != null
-                    && doesPackageSupportRuntimePermissions(imsServicePackage)) {
-                grantRuntimePermissions(imsServicePackage, PHONE_PERMISSIONS, userId);
-                grantRuntimePermissions(imsServicePackage, MICROPHONE_PERMISSIONS, userId);
-                grantRuntimePermissions(imsServicePackage, LOCATION_PERMISSIONS, userId);
-                grantRuntimePermissions(imsServicePackage, CAMERA_PERMISSIONS, userId);
-                grantRuntimePermissions(imsServicePackage, CONTACTS_PERMISSIONS, userId);
-            }
+            grantPermissionsToSystemPackage(packageName, userId,
+                    PHONE_PERMISSIONS, MICROPHONE_PERMISSIONS, LOCATION_PERMISSIONS,
+                    CAMERA_PERMISSIONS, CONTACTS_PERMISSIONS);
         }
     }
 
@@ -1011,15 +825,12 @@
             return;
         }
         for (String packageName : packageNames) {
-            PackageParser.Package dataServicePackage = getSystemPackage(packageName);
-            if (dataServicePackage != null
-                    && doesPackageSupportRuntimePermissions(dataServicePackage)) {
-                // Grant these permissions as system-fixed, so that nobody can accidentally
-                // break cellular data.
-                grantRuntimePermissions(dataServicePackage, PHONE_PERMISSIONS, true, userId);
-                grantRuntimePermissions(dataServicePackage, LOCATION_PERMISSIONS, true, userId);
-            }
+            // Grant these permissions as system-fixed, so that nobody can accidentally
+            // break cellular data.
+            grantSystemFixedPermissionsToSystemPackage(packageName, userId,
+                    PHONE_PERMISSIONS, LOCATION_PERMISSIONS);
         }
+
     }
 
     public void revokeDefaultPermissionsFromDisabledTelephonyDataServices(
@@ -1029,25 +840,17 @@
             return;
         }
         for (String packageName : packageNames) {
-            PackageParser.Package dataServicePackage = getSystemPackage(packageName);
-            if (dataServicePackage != null
-                    && doesPackageSupportRuntimePermissions(dataServicePackage)) {
-                revokeRuntimePermissions(dataServicePackage, PHONE_PERMISSIONS, true, userId);
-                revokeRuntimePermissions(dataServicePackage, LOCATION_PERMISSIONS, true, userId);
+            PackageInfo pkg = getSystemPackageInfo(packageName);
+            if (isSystemPackage(pkg) && doesPackageSupportRuntimePermissions(pkg)) {
+                revokeRuntimePermissions(packageName, PHONE_PERMISSIONS, true, userId);
+                revokeRuntimePermissions(packageName, LOCATION_PERMISSIONS, true, userId);
             }
         }
     }
 
     public void grantDefaultPermissionsToActiveLuiApp(String packageName, int userId) {
         Log.i(TAG, "Granting permissions to active LUI app for user:" + userId);
-        if (packageName == null) {
-            return;
-        }
-        PackageParser.Package luiAppPackage = getSystemPackage(packageName);
-        if (luiAppPackage != null
-                && doesPackageSupportRuntimePermissions(luiAppPackage)) {
-            grantRuntimePermissions(luiAppPackage, CAMERA_PERMISSIONS, true, userId);
-        }
+        grantSystemFixedPermissionsToSystemPackage(packageName, userId, CAMERA_PERMISSIONS);
     }
 
     public void revokeDefaultPermissionsFromLuiApps(String[] packageNames, int userId) {
@@ -1056,123 +859,116 @@
             return;
         }
         for (String packageName : packageNames) {
-            PackageParser.Package luiAppPackage = getSystemPackage(packageName);
-            if (luiAppPackage != null
-                    && doesPackageSupportRuntimePermissions(luiAppPackage)) {
-                revokeRuntimePermissions(luiAppPackage, CAMERA_PERMISSIONS, true, userId);
+            PackageInfo pkg = getSystemPackageInfo(packageName);
+            if (isSystemPackage(pkg) && doesPackageSupportRuntimePermissions(pkg)) {
+                revokeRuntimePermissions(packageName, CAMERA_PERMISSIONS, true, userId);
             }
         }
     }
 
     public void grantDefaultPermissionsToDefaultBrowser(String packageName, int userId) {
         Log.i(TAG, "Granting permissions to default browser for user:" + userId);
-        if (packageName == null) {
-            return;
-        }
-        PackageParser.Package browserPackage = getSystemPackage(packageName);
-        if (browserPackage != null
-                && doesPackageSupportRuntimePermissions(browserPackage)) {
-            grantRuntimePermissions(browserPackage, LOCATION_PERMISSIONS, false, false, userId);
-        }
+        grantPermissionsToSystemPackage(packageName, userId, LOCATION_PERMISSIONS);
     }
 
-    private PackageParser.Package getDefaultSystemHandlerActivityPackage(
-            Intent intent, int userId) {
+    private String getDefaultSystemHandlerActivityPackage(String intentAction, int userId) {
+        return getDefaultSystemHandlerActivityPackage(new Intent(intentAction), userId);
+    }
+
+    private String getDefaultSystemHandlerActivityPackage(Intent intent, int userId) {
         ResolveInfo handler = mServiceInternal.resolveIntent(intent,
-                intent.resolveType(mContext.getContentResolver()), DEFAULT_FLAGS, userId, false,
-                Binder.getCallingUid());
+                intent.resolveType(mContext.getContentResolver()), DEFAULT_INTENT_QUERY_FLAGS,
+                userId, false, Binder.getCallingUid());
         if (handler == null || handler.activityInfo == null) {
             return null;
         }
         if (mServiceInternal.isResolveActivityComponent(handler.activityInfo)) {
             return null;
         }
-        return getSystemPackage(handler.activityInfo.packageName);
+        String packageName = handler.activityInfo.packageName;
+        return isSystemPackage(packageName) ? packageName : null;
     }
 
-    private PackageParser.Package getDefaultSystemHandlerServicePackage(
+    private String getDefaultSystemHandlerServicePackage(String intentAction, int userId) {
+        return getDefaultSystemHandlerServicePackage(new Intent(intentAction), userId);
+    }
+
+    private String getDefaultSystemHandlerServicePackage(
             Intent intent, int userId) {
         List<ResolveInfo> handlers = mServiceInternal.queryIntentServices(
-                intent, DEFAULT_FLAGS, Binder.getCallingUid(), userId);
+                intent, DEFAULT_INTENT_QUERY_FLAGS, Binder.getCallingUid(), userId);
         if (handlers == null) {
             return null;
         }
         final int handlerCount = handlers.size();
         for (int i = 0; i < handlerCount; i++) {
             ResolveInfo handler = handlers.get(i);
-            PackageParser.Package handlerPackage = getSystemPackage(
-                    handler.serviceInfo.packageName);
-            if (handlerPackage != null) {
+            String handlerPackage = handler.serviceInfo.packageName;
+            if (isSystemPackage(handlerPackage)) {
                 return handlerPackage;
             }
         }
         return null;
     }
 
-    private List<PackageParser.Package> getHeadlessSyncAdapterPackages(
+    private ArrayList<String> getHeadlessSyncAdapterPackages(
             String[] syncAdapterPackageNames, int userId) {
-        List<PackageParser.Package> syncAdapterPackages = new ArrayList<>();
+        ArrayList<String> syncAdapterPackages = new ArrayList<>();
 
-        Intent homeIntent = new Intent(Intent.ACTION_MAIN);
-        homeIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+        Intent homeIntent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER);
 
         for (String syncAdapterPackageName : syncAdapterPackageNames) {
             homeIntent.setPackage(syncAdapterPackageName);
 
             ResolveInfo homeActivity = mServiceInternal.resolveIntent(homeIntent,
-                    homeIntent.resolveType(mContext.getContentResolver()), DEFAULT_FLAGS,
+                    homeIntent.resolveType(mContext.getContentResolver()),
+                    DEFAULT_INTENT_QUERY_FLAGS,
                     userId, false, Binder.getCallingUid());
             if (homeActivity != null) {
                 continue;
             }
 
-            PackageParser.Package syncAdapterPackage = getSystemPackage(syncAdapterPackageName);
-            if (syncAdapterPackage != null) {
-                syncAdapterPackages.add(syncAdapterPackage);
+            if (isSystemPackage(syncAdapterPackageName)) {
+                syncAdapterPackages.add(syncAdapterPackageName);
             }
         }
 
         return syncAdapterPackages;
     }
 
-    private PackageParser.Package getDefaultProviderAuthorityPackage(
-            String authority, int userId) {
-        ProviderInfo provider =
-                mServiceInternal.resolveContentProvider(authority, DEFAULT_FLAGS, userId);
+    private String getDefaultProviderAuthorityPackage(String authority, int userId) {
+        ProviderInfo provider = mServiceInternal.resolveContentProvider(
+                authority, DEFAULT_INTENT_QUERY_FLAGS, userId);
         if (provider != null) {
-            return getSystemPackage(provider.packageName);
+            return provider.packageName;
         }
         return null;
     }
 
-    private PackageParser.Package getPackage(String packageName) {
-        return mServiceInternal.getPackage(packageName);
+    private boolean isSystemPackage(String packageName) {
+        return isSystemPackage(getPackageInfo(packageName));
     }
 
-    private PackageParser.Package getSystemPackage(String packageName) {
-        PackageParser.Package pkg = getPackage(packageName);
-        if (pkg != null && pkg.isSystem()) {
-            return !isSysComponentOrPersistentPlatformSignedPrivApp(pkg) ? pkg : null;
+    private boolean isSystemPackage(PackageInfo pkg) {
+        if (pkg == null) {
+            return false;
         }
-        return null;
+        return pkg.applicationInfo.isSystemApp()
+                && !isSysComponentOrPersistentPlatformSignedPrivApp(pkg);
     }
 
-    private void grantRuntimePermissions(PackageParser.Package pkg, Set<String> permissions,
-            int userId) {
-        grantRuntimePermissions(pkg, permissions, false, false, userId);
-    }
-
-    private void grantRuntimePermissions(PackageParser.Package pkg, Set<String> permissions,
+    private void grantRuntimePermissions(PackageInfo pkg, Set<String> permissions,
             boolean systemFixed, int userId) {
         grantRuntimePermissions(pkg, permissions, systemFixed, false, userId);
     }
 
-    private void revokeRuntimePermissions(PackageParser.Package pkg, Set<String> permissions,
+    private void revokeRuntimePermissions(String packageName, Set<String> permissions,
             boolean systemFixed, int userId) {
-        if (pkg.requestedPermissions.isEmpty()) {
+        PackageInfo pkg = getSystemPackageInfo(packageName);
+        if (ArrayUtils.isEmpty(pkg.requestedPermissions)) {
             return;
         }
-        Set<String> revokablePermissions = new ArraySet<>(pkg.requestedPermissions);
+        Set<String> revokablePermissions = new ArraySet<>(Arrays.asList(pkg.requestedPermissions));
 
         for (String permission : permissions) {
             // We can't revoke what wasn't requested.
@@ -1181,7 +977,7 @@
             }
 
             final int flags = mServiceInternal.getPermissionFlagsTEMP(
-                    permission, pkg.packageName, userId);
+                    permission, packageName, userId);
 
             // We didn't get this through the default grant policy. Move along.
             if ((flags & PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT) == 0) {
@@ -1197,43 +993,51 @@
             if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0 && !systemFixed) {
                 continue;
             }
-            mServiceInternal.revokeRuntimePermission(pkg.packageName, permission, userId, false);
+            mServiceInternal.revokeRuntimePermission(packageName, permission, userId, false);
 
             if (DEBUG) {
                 Log.i(TAG, "revoked " + (systemFixed ? "fixed " : "not fixed ")
-                        + permission + " to " + pkg.packageName);
+                        + permission + " to " + packageName);
             }
 
             // Remove the GRANTED_BY_DEFAULT flag without touching the others.
             // Note that we do not revoke FLAG_PERMISSION_SYSTEM_FIXED. That bit remains
             // sticky once set.
-            mServiceInternal.updatePermissionFlagsTEMP(permission, pkg.packageName,
+            mServiceInternal.updatePermissionFlagsTEMP(permission, packageName,
                     PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, 0, userId);
         }
     }
 
-    private void grantRuntimePermissions(PackageParser.Package pkg,
+    private void grantRuntimePermissions(PackageInfo pkg,
             Set<String> permissionsWithoutSplits, boolean systemFixed, boolean ignoreSystemPackage,
             int userId) {
-        if (pkg.requestedPermissions.isEmpty()) {
+        if (pkg == null) {
+            return;
+        }
+
+        String[] requestedPermissions = pkg.requestedPermissions;
+        if (ArrayUtils.isEmpty(requestedPermissions)) {
             return;
         }
 
         final ArraySet<String> permissions = new ArraySet<>(permissionsWithoutSplits);
+        ApplicationInfo applicationInfo = pkg.applicationInfo;
 
         // Automatically attempt to grant split permissions to older APKs
-        final int numSplitPerms = PackageParser.SPLIT_PERMISSIONS.length;
+        final List<PermissionManager.SplitPermissionInfo> splitPermissions =
+                mContext.getSystemService(PermissionManager.class).getSplitPermissions();
+        final int numSplitPerms = splitPermissions.size();
         for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) {
-            final PackageParser.SplitPermissionInfo splitPerm =
-                    PackageParser.SPLIT_PERMISSIONS[splitPermNum];
+            final PermissionManager.SplitPermissionInfo splitPerm =
+                    splitPermissions.get(splitPermNum);
 
-            if (pkg.applicationInfo.targetSdkVersion < splitPerm.targetSdk
-                    && permissionsWithoutSplits.contains(splitPerm.rootPerm)) {
-                Collections.addAll(permissions, splitPerm.newPerms);
+            if (applicationInfo != null
+                    && applicationInfo.targetSdkVersion < splitPerm.getTargetSdk()
+                    && permissionsWithoutSplits.contains(splitPerm.getRootPermission())) {
+                Collections.addAll(permissions, splitPerm.getNewPermissions());
             }
         }
 
-        List<String> requestedPermissions = pkg.requestedPermissions;
         Set<String> grantablePermissions = null;
 
         // In some cases, like for the Phone or SMS app, we grant permissions regardless
@@ -1242,23 +1046,25 @@
         // choice to grant this app the permissions needed to function. For all other
         // apps, (default grants on first boot and user creation) we don't grant default
         // permissions if the version on the system image does not declare them.
-        if (!ignoreSystemPackage && pkg.isUpdatedSystemApp()) {
-            final PackageParser.Package disabledPkg =
-                    mServiceInternal.getDisabledPackage(pkg.packageName);
+        if (!ignoreSystemPackage
+                && applicationInfo != null
+                && applicationInfo.isUpdatedSystemApp()) {
+            final PackageInfo disabledPkg = getSystemPackageInfo(
+                    mServiceInternal.getDisabledSystemPackageName(pkg.packageName));
             if (disabledPkg != null) {
-                if (disabledPkg.requestedPermissions.isEmpty()) {
+                if (ArrayUtils.isEmpty(disabledPkg.requestedPermissions)) {
                     return;
                 }
                 if (!requestedPermissions.equals(disabledPkg.requestedPermissions)) {
-                    grantablePermissions = new ArraySet<>(requestedPermissions);
+                    grantablePermissions = new ArraySet<>(Arrays.asList(requestedPermissions));
                     requestedPermissions = disabledPkg.requestedPermissions;
                 }
             }
         }
 
-        final int grantablePermissionCount = requestedPermissions.size();
+        final int grantablePermissionCount = requestedPermissions.length;
         for (int i = 0; i < grantablePermissionCount; i++) {
-            String permission = requestedPermissions.get(i);
+            String permission = requestedPermissions[i];
 
             // If there is a disabled system app it may request a permission the updated
             // version ot the data partition doesn't, In this case skip the permission.
@@ -1288,7 +1094,7 @@
                             pkg.packageName, permission, userId, false);
                     if (DEBUG) {
                         Log.i(TAG, "Granted " + (systemFixed ? "fixed " : "not fixed ")
-                                + permission + " to default handler " + pkg.packageName);
+                                + permission + " to default handler " + pkg);
                     }
 
                     int newFlags = PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
@@ -1307,7 +1113,7 @@
                         && !systemFixed) {
                     if (DEBUG) {
                         Log.i(TAG, "Granted not fixed " + permission + " to default handler "
-                                + pkg.packageName);
+                                + pkg);
                     }
                     mServiceInternal.updatePermissionFlagsTEMP(permission, pkg.packageName,
                             PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, 0, userId);
@@ -1316,28 +1122,42 @@
         }
     }
 
-    private boolean isSysComponentOrPersistentPlatformSignedPrivApp(PackageParser.Package pkg) {
+    private PackageInfo getSystemPackageInfo(String pkg) {
+        //TODO not MATCH_SYSTEM_ONLY?
+        return getPackageInfo(pkg, PackageManager.MATCH_FACTORY_ONLY);
+    }
+
+    private PackageInfo getPackageInfo(String pkg) {
+        return getPackageInfo(pkg, 0 /* extraFlags */);
+    }
+
+    private PackageInfo getPackageInfo(String pkg,
+            @PackageManager.PackageInfoFlags int extraFlags) {
+        return mServiceInternal.getPackageInfo(pkg,
+                DEFAULT_PACKAGE_INFO_QUERY_FLAGS | extraFlags,
+                //TODO is this the right filterCallingUid?
+                UserHandle.USER_SYSTEM, UserHandle.USER_SYSTEM);
+    }
+
+    private boolean isSysComponentOrPersistentPlatformSignedPrivApp(PackageInfo pkg) {
         if (UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) {
             return true;
         }
-        if (!pkg.isPrivileged()) {
+        if (!pkg.applicationInfo.isPrivilegedApp()) {
             return false;
         }
-        final PackageParser.Package disabledPkg =
-                mServiceInternal.getDisabledPackage(pkg.packageName);
+        final PackageInfo disabledPkg = getSystemPackageInfo(
+                mServiceInternal.getDisabledSystemPackageName(pkg.applicationInfo.packageName));
         if (disabledPkg != null) {
-            if ((disabledPkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) {
+            ApplicationInfo disabledPackageAppInfo = disabledPkg.applicationInfo;
+            if (disabledPackageAppInfo != null
+                    && (disabledPackageAppInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) {
                 return false;
             }
         } else if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) {
             return false;
         }
-        final String systemPackageName = mServiceInternal.getKnownPackageName(
-                PackageManagerInternal.PACKAGE_SYSTEM, UserHandle.USER_SYSTEM);
-        final PackageParser.Package systemPackage = getPackage(systemPackageName);
-        return pkg.mSigningDetails.hasAncestorOrSelf(systemPackage.mSigningDetails)
-                || systemPackage.mSigningDetails.checkCapability(pkg.mSigningDetails,
-                        PackageParser.SigningDetails.CertCapabilities.PERMISSION);
+        return mServiceInternal.isPlatformSigned(pkg.packageName);
     }
 
     private void grantDefaultPermissionExceptions(int userId) {
@@ -1357,7 +1177,7 @@
         final int exceptionCount = mGrantExceptions.size();
         for (int i = 0; i < exceptionCount; i++) {
             String packageName = mGrantExceptions.keyAt(i);
-            PackageParser.Package pkg = getSystemPackage(packageName);
+            PackageInfo pkg = getSystemPackageInfo(packageName);
             List<DefaultPermissionGrant> permissionGrants = mGrantExceptions.valueAt(i);
             final int permissionGrantCount = permissionGrants.size();
             for (int j = 0; j < permissionGrantCount; j++) {
@@ -1368,8 +1188,7 @@
                     permissions.clear();
                 }
                 permissions.add(permissionGrant.name);
-                grantRuntimePermissions(pkg, permissions,
-                        permissionGrant.fixed, userId);
+                grantRuntimePermissions(pkg, permissions, permissionGrant.fixed, userId);
             }
         }
     }
@@ -1474,15 +1293,14 @@
                         outGrantExceptions.get(packageName);
                 if (packageExceptions == null) {
                     // The package must be on the system image
-                    PackageParser.Package pkg = getSystemPackage(packageName);
-                    if (pkg == null) {
+                    if (!isSystemPackage(packageName)) {
                         Log.w(TAG, "Unknown package:" + packageName);
                         XmlUtils.skipCurrentTag(parser);
                         continue;
                     }
 
                     // The package must support runtime permissions
-                    if (!doesPackageSupportRuntimePermissions(pkg)) {
+                    if (!doesPackageSupportRuntimePermissions(getSystemPackageInfo(packageName))) {
                         Log.w(TAG, "Skipping non supporting runtime permissions package:"
                                 + packageName);
                         XmlUtils.skipCurrentTag(parser);
@@ -1527,8 +1345,9 @@
         }
     }
 
-    private static boolean doesPackageSupportRuntimePermissions(PackageParser.Package pkg) {
-        return pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1;
+    private static boolean doesPackageSupportRuntimePermissions(PackageInfo pkg) {
+        return pkg.applicationInfo != null
+                && pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1;
     }
 
     private static final class DefaultPermissionGrant {
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 c4f90a12..4b6760c 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1189,7 +1189,7 @@
                 // is granted only if it had been defined by the original application.
                 if (pkg.isUpdatedSystemApp()) {
                     final PackageParser.Package disabledPkg =
-                            mPackageManagerInt.getDisabledPackage(pkg.packageName);
+                            mPackageManagerInt.getDisabledSystemPackage(pkg.packageName);
                     final PackageSetting disabledPs =
                             (disabledPkg != null) ? (PackageSetting) disabledPkg.mExtras : null;
                     if (disabledPs != null
@@ -1221,7 +1221,7 @@
                         // packages can also get the permission.
                         if (pkg.parentPackage != null) {
                             final PackageParser.Package disabledParentPkg = mPackageManagerInt
-                                    .getDisabledPackage(pkg.parentPackage.packageName);
+                                    .getDisabledSystemPackage(pkg.parentPackage.packageName);
                             final PackageSetting disabledParentPs = (disabledParentPkg != null)
                                     ? (PackageSetting) disabledParentPkg.mExtras : null;
                             if (disabledParentPkg != null
@@ -1372,7 +1372,7 @@
             return;
         }
         final PackageParser.Package disabledPkg =
-                mPackageManagerInt.getDisabledPackage(pkg.parentPackage.packageName);
+                mPackageManagerInt.getDisabledSystemPackage(pkg.parentPackage.packageName);
         if (disabledPkg == null || disabledPkg.mExtras == null) {
             return;
         }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 350d6b6..2557f46 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -125,6 +125,7 @@
 import static android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION;
 import static android.view.WindowManagerGlobal.ADD_OKAY;
 import static android.view.WindowManagerGlobal.ADD_PERMISSION_DENIED;
+
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
@@ -532,8 +533,6 @@
 
     GlobalActions mGlobalActions;
     Handler mHandler;
-    WindowState mLastInputMethodWindow = null;
-    WindowState mLastInputMethodTargetWindow = null;
 
     // FIXME This state is shared between the input reader and handler thread.
     // Technically it's broken and buggy but it has been like this for many years
@@ -631,9 +630,11 @@
 
     InputConsumer mInputConsumer = null;
 
-    private final WindowFrames mWindowFrames = new WindowFrames();
-    private static final Rect mTmpDisplayCutoutSafeExceptMaybeBarsRect = new Rect();
-    private static final Rect mTmpRect = new Rect();
+    private static final Rect sTmpDisplayCutoutSafeExceptMaybeBarsRect = new Rect();
+    private static final Rect sTmpRect = new Rect();
+    private static final Rect sTmpDockedFrame = new Rect();
+    private static final Rect sTmpNavFrame = new Rect();
+    private static final Rect sTmpLastParentFrame = new Rect();
 
     WindowState mTopFullscreenOpaqueWindowState;
     WindowState mTopFullscreenOpaqueOrDimmingWindowState;
@@ -2827,7 +2828,8 @@
                 // Assumes it's safe to show starting windows of launched apps while
                 // the keyguard is being hidden. This is okay because starting windows never show
                 // secret information.
-                if (mKeyguardOccluded) {
+                // TODO(b/113840485): Occluded may not only happen on default display
+                if (displayId == DEFAULT_DISPLAY && mKeyguardOccluded) {
                     windowFlags |= FLAG_SHOW_WHEN_LOCKED;
                 }
             }
@@ -3543,8 +3545,6 @@
             return 0;
         } else if (mHasFeatureLeanback && interceptBugreportGestureTv(keyCode, down)) {
             return -1;
-        } else if (mHasFeatureLeanback && interceptAccessibilityGestureTv(keyCode, down)) {
-            return -1;
         } else if (keyCode == KeyEvent.KEYCODE_ALL_APPS) {
             if (!down) {
                 mHandler.removeMessages(MSG_HANDLE_ALL_APPS);
@@ -4310,9 +4310,6 @@
         mDockLayer = 0x10000000;
         mStatusBarLayer = -1;
 
-        mWindowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
-        mWindowFrames.setParentFrameWasClippedByDisplayCutout(false);
-
         if (displayFrames.mDisplayId == DEFAULT_DISPLAY) {
             // For purposes of putting out fake window up to steal focus, we will
             // drive nav being hidden only by whether it is requested.
@@ -4379,12 +4376,8 @@
             return;
         }
 
-        mTmpRect.setEmpty();
-        mWindowFrames.setFrames(displayFrames.mDock /* parentFrame */,
-                displayFrames.mDock /* displayFrame */, displayFrames.mDock /* overscanFrame */,
-                displayFrames.mDock /* contentFrame */, displayFrames.mDock /* visibleFrame */,
-                mTmpRect /* decorFrame */, displayFrames.mDock /* stableFrame */,
-                displayFrames.mDock /* outsetFrame */);
+        sTmpRect.setEmpty();
+        sTmpDockedFrame.set(displayFrames.mDock);
 
         final int displayId = displayFrames.mDisplayId;
         final Rect dockFrame = displayFrames.mDock;
@@ -4398,7 +4391,13 @@
                 continue;
             }
 
-            w.computeFrameLw(mWindowFrames);
+            w.getWindowFrames().setFrames(sTmpDockedFrame /* parentFrame */,
+                    sTmpDockedFrame /* displayFrame */, sTmpDockedFrame /* overscanFrame */,
+                    sTmpDockedFrame /* contentFrame */, sTmpDockedFrame /* visibleFrame */,
+                    sTmpRect /* decorFrame */, sTmpDockedFrame /* stableFrame */,
+                    sTmpDockedFrame /* outsetFrame */);
+            w.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
+            w.computeFrameLw();
             final Rect frame = w.getFrameLw();
 
             if (frame.left <= 0 && frame.top <= 0) {
@@ -4450,17 +4449,17 @@
             return false;
         }
         // apply any navigation bar insets
-        mTmpRect.setEmpty();
-        mWindowFrames.setFrames(displayFrames.mUnrestricted /* parentFrame */,
+        sTmpRect.setEmpty();
+        mStatusBar.getWindowFrames().setFrames(displayFrames.mUnrestricted /* parentFrame */,
                 displayFrames.mUnrestricted /* displayFrame */,
                 displayFrames.mStable /* overscanFrame */, displayFrames.mStable /* contentFrame */,
-                displayFrames.mStable /* visibleFrame */, mTmpRect /* decorFrame */,
+                displayFrames.mStable /* visibleFrame */, sTmpRect /* decorFrame */,
                 displayFrames.mStable /* stableFrame */, displayFrames.mStable /* outsetFrame */);
-
+        mStatusBar.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
         mStatusBarLayer = mStatusBar.getSurfaceLayer();
 
         // Let the status bar determine its size.
-        mStatusBar.computeFrameLw(mWindowFrames);
+        mStatusBar.computeFrameLw();
 
         // For layout, the status bar is always at the top with our fixed height.
         displayFrames.mStable.top = displayFrames.mUnrestricted.top
@@ -4470,11 +4469,11 @@
                 displayFrames.mDisplayCutoutSafe.top);
 
         // Tell the bar controller where the collapsed status bar content is
-        mTmpRect.set(mStatusBar.getContentFrameLw());
-        mTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
-        mTmpRect.top = mStatusBar.getContentFrameLw().top;  // Ignore top display cutout inset
-        mTmpRect.bottom = displayFrames.mStable.top;  // Use collapsed status bar size
-        mStatusBarController.setContentFrame(mTmpRect);
+        sTmpRect.set(mStatusBar.getContentFrameLw());
+        sTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
+        sTmpRect.top = mStatusBar.getContentFrameLw().top;  // Ignore top display cutout inset
+        sTmpRect.bottom = displayFrames.mStable.top;  // Use collapsed status bar size
+        mStatusBarController.setContentFrame(sTmpRect);
 
         boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0;
         boolean statusBarTranslucent = (sysui
@@ -4514,7 +4513,7 @@
             return false;
         }
 
-        final Rect navigationFrame = mWindowFrames.mParentFrame;
+        final Rect navigationFrame = sTmpNavFrame;
         boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();
         // Force the navigation bar to its appropriate place and size. We need to do this directly,
         // instead of relying on it to bubble up from the nav bar, because this needs to change
@@ -4525,7 +4524,7 @@
         final Rect dockFrame = displayFrames.mDock;
         mNavigationBarPosition = navigationBarPosition(displayWidth, displayHeight, rotation);
 
-        final Rect cutoutSafeUnrestricted = mTmpRect;
+        final Rect cutoutSafeUnrestricted = sTmpRect;
         cutoutSafeUnrestricted.set(displayFrames.mUnrestricted);
         cutoutSafeUnrestricted.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
 
@@ -4607,15 +4606,15 @@
         displayFrames.mContent.set(dockFrame);
         mStatusBarLayer = mNavigationBar.getSurfaceLayer();
         // And compute the final frame.
-        mTmpRect.setEmpty();
-        mWindowFrames.setFrames(navigationFrame /* parentFrame */,
+        sTmpRect.setEmpty();
+        mNavigationBar.getWindowFrames().setFrames(navigationFrame /* parentFrame */,
                 navigationFrame /* displayFrame */, navigationFrame /* overscanFrame */,
                 displayFrames.mDisplayCutoutSafe /* contentFrame */,
-                navigationFrame /* visibleFrame */, mTmpRect /* decorFrame */,
+                navigationFrame /* visibleFrame */, sTmpRect /* decorFrame */,
                 navigationFrame /* stableFrame */,
                 displayFrames.mDisplayCutoutSafe /* outsetFrame */);
-
-        mNavigationBar.computeFrameLw(mWindowFrames);
+        mNavigationBar.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
+        mNavigationBar.computeFrameLw();
         mNavigationBarController.setContentFrame(mNavigationBar.getContentFrameLw());
 
         if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + navigationFrame);
@@ -4732,12 +4731,6 @@
         }
         final WindowManager.LayoutParams attrs = win.getAttrs();
         final boolean isDefaultDisplay = win.isDefaultDisplay();
-        final boolean needsToOffsetInputMethodTarget =
-                (win == mLastInputMethodTargetWindow) && (mLastInputMethodWindow != null);
-        if (needsToOffsetInputMethodTarget) {
-            if (DEBUG_LAYOUT) Slog.i(TAG, "Offset ime target window by the last ime window state");
-            offsetInputMethodWindowLw(mLastInputMethodWindow, displayFrames);
-        }
 
         final int type = attrs.type;
         final int fl = PolicyControl.getWindowFlags(win, attrs);
@@ -4746,17 +4739,20 @@
         final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(null, attrs);
         final int sysUiFl = requestedSysUiFl | getImpliedSysUiFlagsForLayout(attrs);
 
-        final Rect pf = mWindowFrames.mParentFrame;
-        final Rect df = mWindowFrames.mDisplayFrame;
-        final Rect of = mWindowFrames.mOverscanFrame;
-        final Rect cf = mWindowFrames.mContentFrame;
-        final Rect vf = mWindowFrames.mVisibleFrame;
-        final Rect dcf = mWindowFrames.mDecorFrame;
-        final Rect sf = mWindowFrames.mStableFrame;
+        final WindowFrames windowFrames = win.getWindowFrames();
+
+        windowFrames.setHasOutsets(false);
+        sTmpLastParentFrame.set(windowFrames.mParentFrame);
+        final Rect pf = windowFrames.mParentFrame;
+        final Rect df = windowFrames.mDisplayFrame;
+        final Rect of = windowFrames.mOverscanFrame;
+        final Rect cf = windowFrames.mContentFrame;
+        final Rect vf = windowFrames.mVisibleFrame;
+        final Rect dcf = windowFrames.mDecorFrame;
+        final Rect sf = windowFrames.mStableFrame;
         dcf.setEmpty();
-        mWindowFrames.mOutsetFrame.setEmpty();
-        mWindowFrames.setParentFrameWasClippedByDisplayCutout(false);
-        mWindowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
+        windowFrames.setParentFrameWasClippedByDisplayCutout(false);
+        windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
 
         final boolean hasNavBar = (isDefaultDisplay && mDefaultDisplayPolicy.hasNavigationBar()
                 && mNavigationBar != null && mNavigationBar.isVisibleLw());
@@ -4776,7 +4772,7 @@
             cf.set(displayFrames.mDock);
             of.set(displayFrames.mDock);
             df.set(displayFrames.mDock);
-            pf.set(displayFrames.mDock);
+            windowFrames.mParentFrame.set(displayFrames.mDock);
             // IM dock windows layout below the nav bar...
             pf.bottom = df.bottom = of.bottom = displayFrames.mUnrestricted.bottom;
             // ...with content insets above the nav bar
@@ -4878,9 +4874,7 @@
                                 ? displayFrames.mRestricted.bottom
                                 : displayFrames.mUnrestricted.bottom;
 
-                        if (DEBUG_LAYOUT) Slog.v(TAG, String.format(
-                                        "Laying out status bar window: (%d,%d - %d,%d)",
-                                        pf.left, pf.top, pf.right, pf.bottom));
+                        if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out status bar window: " + pf);
                     } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
                             && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) {
                         // Asking to layout into the overscan region, so give it that pure
@@ -4952,17 +4946,13 @@
                         pf.bottom = df.bottom = of.bottom = cf.bottom =
                                 displayFrames.mRestricted.bottom;
                     }
-                    if (DEBUG_LAYOUT) Slog.v(TAG, String.format(
-                            "Laying out IN_SCREEN status bar window: (%d,%d - %d,%d)",
-                            pf.left, pf.top, pf.right, pf.bottom));
+                    if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out IN_SCREEN status bar window: " + pf);
                 } else if (type == TYPE_NAVIGATION_BAR || type == TYPE_NAVIGATION_BAR_PANEL) {
                     // The navigation bar has Real Ultimate Power.
                     of.set(displayFrames.mUnrestricted);
                     df.set(displayFrames.mUnrestricted);
                     pf.set(displayFrames.mUnrestricted);
-                    if (DEBUG_LAYOUT) Slog.v(TAG, String.format(
-                                    "Laying out navigation bar window: (%d,%d - %d,%d)",
-                                    pf.left, pf.top, pf.right, pf.bottom));
+                    if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out navigation bar window: " + pf);
                 } else if ((type == TYPE_SECURE_SYSTEM_OVERLAY || type == TYPE_SCREENSHOT)
                         && ((fl & FLAG_FULLSCREEN) != 0)) {
                     // Fullscreen secure system overlays get what they ask for. Screenshot region
@@ -5089,7 +5079,7 @@
         // Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in
         // the cutout safe zone.
         if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) {
-            final Rect displayCutoutSafeExceptMaybeBars = mTmpDisplayCutoutSafeExceptMaybeBarsRect;
+            final Rect displayCutoutSafeExceptMaybeBars = sTmpDisplayCutoutSafeExceptMaybeBarsRect;
             displayCutoutSafeExceptMaybeBars.set(displayFrames.mDisplayCutoutSafe);
             if (layoutInScreen && layoutInsetDecor && !requestedFullscreen
                     && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
@@ -5124,9 +5114,9 @@
             // They will later be cropped or shifted using the displayFrame in WindowState,
             // which prevents overlap with the DisplayCutout.
             if (!attachedInParent && !floatingInScreenWindow) {
-                mTmpRect.set(pf);
+                sTmpRect.set(pf);
                 pf.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
-                mWindowFrames.setParentFrameWasClippedByDisplayCutout(!mTmpRect.equals(pf));
+                windowFrames.setParentFrameWasClippedByDisplayCutout(!sTmpRect.equals(pf));
             }
             // Make sure that NO_LIMITS windows clipped to the display don't extend under the
             // cutout.
@@ -5154,8 +5144,9 @@
         // apply the outsets to floating dialogs, because they wouldn't make sense there.
         final boolean useOutsets = shouldUseOutsets(attrs, fl);
         if (isDefaultDisplay && useOutsets) {
-            final Rect osf = mWindowFrames.mOutsetFrame;
+            final Rect osf = windowFrames.mOutsetFrame;
             osf.set(cf.left, cf.top, cf.right, cf.bottom);
+            windowFrames.setHasOutsets(true);
             int outset = ScreenShapeHelper.getWindowOutsetBottomPx(mContext.getResources());
             if (outset > 0) {
                 int rotation = displayFrames.mRotation;
@@ -5182,14 +5173,17 @@
                 + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()
                 + " dcf=" + dcf.toShortString()
                 + " sf=" + sf.toShortString()
-                + " osf=" + mWindowFrames.mOutsetFrame.toShortString());
+                + " osf=" + windowFrames.mOutsetFrame.toShortString() + " " + win);
 
-        win.computeFrameLw(mWindowFrames);
+        if (!sTmpLastParentFrame.equals(pf)) {
+            windowFrames.setContentChanged(true);
+        }
+
+        win.computeFrameLw();
         // Dock windows carve out the bottom of the screen, so normal windows
         // can't appear underneath them.
         if (type == TYPE_INPUT_METHOD && win.isVisibleLw()
                 && !win.getGivenInsetsPendingLw()) {
-            setLastInputMethodWindowLw(null, null);
             offsetInputMethodWindowLw(win, displayFrames);
         }
         if (type == TYPE_VOICE_INTERACTION && win.isVisibleLw()
@@ -6037,6 +6031,22 @@
             }
         }
 
+        // Intercept the Accessibility keychord for TV (DPAD_DOWN + Back) before the keyevent is
+        // processed through interceptKeyEventBeforeDispatch since Talkback may consume this event
+        // before it has a chance to reach that method.
+        if (mHasFeatureLeanback) {
+            switch (keyCode) {
+                case KeyEvent.KEYCODE_DPAD_DOWN:
+                case KeyEvent.KEYCODE_BACK: {
+                    boolean handled = interceptAccessibilityGestureTv(keyCode, down);
+                    if (handled) {
+                        result &= ~ACTION_PASS_TO_USER;
+                    }
+                    break;
+                }
+            }
+        }
+
         if (useHapticFeedback) {
             performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false,
                     "Virtual Key - Press");
@@ -7804,12 +7814,6 @@
     }
 
     @Override
-    public void setLastInputMethodWindowLw(WindowState ime, WindowState target) {
-        mLastInputMethodWindow = ime;
-        mLastInputMethodTargetWindow = target;
-    }
-
-    @Override
     public void setDismissImeOnBackKeyPressed(boolean newValue) {
         mDismissImeOnBackKeyPressed = newValue;
     }
@@ -7827,7 +7831,6 @@
         if (statusBar != null) {
             statusBar.setCurrentUser(newUserId);
         }
-        setLastInputMethodWindowLw(null, null);
     }
 
     @Override
@@ -8002,14 +8005,6 @@
         pw.print(prefix); pw.print("mShowingDream="); pw.print(mShowingDream);
                 pw.print(" mDreamingLockscreen="); pw.print(mDreamingLockscreen);
                 pw.print(" mDreamingSleepToken="); pw.println(mDreamingSleepToken);
-        if (mLastInputMethodWindow != null) {
-            pw.print(prefix); pw.print("mLastInputMethodWindow=");
-                    pw.println(mLastInputMethodWindow);
-        }
-        if (mLastInputMethodTargetWindow != null) {
-            pw.print(prefix); pw.print("mLastInputMethodTargetWindow=");
-                    pw.println(mLastInputMethodTargetWindow);
-        }
         if (mStatusBar != null) {
             pw.print(prefix); pw.print("mStatusBar=");
                     pw.print(mStatusBar); pw.print(" isStatusBarKeyguard=");
diff --git a/services/core/java/com/android/server/policy/TEST_MAPPING b/services/core/java/com/android/server/policy/TEST_MAPPING
new file mode 100644
index 0000000..e212b04
--- /dev/null
+++ b/services/core/java/com/android/server/policy/TEST_MAPPING
@@ -0,0 +1,50 @@
+{
+  "presubmit": [
+    {
+      "name": "FrameworksServicesTests",
+      "options": [
+        {
+          "include-filter": "com.android.server.policy."
+        },
+        {
+          "include-annotation": "android.platform.test.annotations.Presubmit"
+        },
+        {
+          "exclude-annotation": "android.support.test.filters.FlakyTest"
+        }
+      ]
+    },
+    {
+      "name": "WmTests",
+      "options": [
+        {
+          "include-filter": "com.android.server.policy."
+        },
+        {
+          "include-annotation": "android.platform.test.annotations.Presubmit"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    }
+  ],
+  "postsubmit": [
+    {
+      "name": "FrameworksServicesTests",
+      "options": [
+        {
+          "include-filter": "com.android.server.policy."
+        }
+      ]
+    },
+    {
+      "name": "WmTests",
+      "options": [
+        {
+          "include-filter": "com.android.server.policy."
+        }
+      ]
+    }
+  ]
+}
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index b55adeb..27ab3ef 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -63,12 +63,10 @@
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
-import android.Manifest;
 import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.content.Context;
-import android.content.pm.ActivityInfo;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.graphics.Rect;
@@ -95,7 +93,6 @@
 import com.android.server.wm.DisplayFrames;
 import com.android.server.wm.DisplayRotation;
 import com.android.server.wm.WindowFrames;
-import com.android.server.wm.utils.WmDisplayCutout;
 
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -201,10 +198,8 @@
          * getFrame() if so desired.  Must be called with the window manager
          * lock held.
          *
-         * @param windowFrames Container for all the window frames that affect how the window is
-         *                     laid out.
          */
-        public void computeFrameLw(WindowFrames windowFrames);
+        public void computeFrameLw();
 
         /**
          * Retrieve the current frame of the window that has been assigned by
@@ -477,6 +472,11 @@
          * Writes {@link com.android.server.wm.IdentifierProto} to stream.
          */
         void writeIdentifierToProto(ProtoOutputStream proto, long fieldId);
+
+        /**
+         * @return The {@link WindowFrames} associated with this {@link WindowState}
+         */
+        WindowFrames getWindowFrames();
     }
 
     /**
@@ -1167,7 +1167,6 @@
     default void layoutWindowLw(
             WindowState win, WindowState attached, DisplayFrames displayFrames) {}
 
-
     /**
      * Return the layout hints for a newly added window. These values are computed on the
      * most recent layout, so they are not guaranteed to be correct.
@@ -1537,13 +1536,6 @@
     public void lockNow(Bundle options);
 
     /**
-     * Set the last used input method window state. This state is used to make IME transition
-     * smooth.
-     * @hide
-     */
-    public void setLastInputMethodWindowLw(WindowState ime, WindowState target);
-
-    /**
      * An internal callback (from InputMethodManagerService) to notify a state change regarding
      * whether the back key should dismiss the software keyboard (IME) or not.
      *
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 5981ab0..5adc248 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -49,6 +49,7 @@
 import android.util.Slog;
 import android.util.StatsLog;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -75,7 +76,8 @@
  * tell the system when we go to sleep so that it can lock the keyguard if needed.
  * </p>
  */
-final class Notifier {
+@VisibleForTesting
+public class Notifier {
     private static final String TAG = "PowerManagerNotifier";
 
     private static final boolean DEBUG = false;
@@ -188,6 +190,8 @@
         try {
             mBatteryStats.noteInteractive(true);
         } catch (RemoteException ex) { }
+        StatsLog.write(StatsLog.INTERACTIVE_STATE_CHANGED,
+                StatsLog.INTERACTIVE_STATE_CHANGED__STATE__ON);
     }
 
     /**
@@ -399,6 +403,9 @@
             try {
                 mBatteryStats.noteInteractive(interactive);
             } catch (RemoteException ex) { }
+            StatsLog.write(StatsLog.INTERACTIVE_STATE_CHANGED,
+                    interactive ? StatsLog.INTERACTIVE_STATE_CHANGED__STATE__ON :
+                            StatsLog.INTERACTIVE_STATE_CHANGED__STATE__OFF);
 
             // Handle early behaviors.
             mInteractive = interactive;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index bdf12ca..9f6b3dd 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -64,7 +64,6 @@
 import android.os.WorkSource;
 import android.os.WorkSource.WorkChain;
 import android.provider.Settings;
-import android.provider.Settings.Global;
 import android.provider.Settings.SettingNotFoundException;
 import android.service.dreams.DreamManagerInternal;
 import android.service.vr.IVrManager;
@@ -84,7 +83,6 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.os.BackgroundThread;
-import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.server.EventLogTags;
 import com.android.server.LockGuard;
@@ -230,6 +228,10 @@
     private final BatterySaverController mBatterySaverController;
     private final BatterySaverStateMachine mBatterySaverStateMachine;
     private final BatterySavingStats mBatterySavingStats;
+    private final BinderService mBinderService;
+    private final LocalService mLocalService;
+    private final NativeWrapper mNativeWrapper;
+    private final Injector mInjector;
 
     private LightsManager mLightsManager;
     private BatteryManagerInternal mBatteryManagerInternal;
@@ -636,10 +638,76 @@
         }
     }
 
+    /**
+     * Wrapper around the static-native methods of PowerManagerService.
+     *
+     * This class exists to allow us to mock static native methods in our tests. If mocking static
+     * methods becomes easier than this in the future, we can delete this class.
+     */
+    @VisibleForTesting
+    public static class NativeWrapper {
+        /** Wrapper for PowerManager.nativeInit */
+        public void nativeInit(PowerManagerService service) {
+            service.nativeInit();
+        }
+
+        /** Wrapper for PowerManager.nativeAcquireSuspectBlocker */
+        public void nativeAcquireSuspendBlocker(String name) {
+            PowerManagerService.nativeAcquireSuspendBlocker(name);
+        }
+
+        /** Wrapper for PowerManager.nativeReleaseSuspendBlocker */
+        public void nativeReleaseSuspendBlocker(String name) {
+            PowerManagerService.nativeReleaseSuspendBlocker(name);
+        }
+
+        /** Wrapper for PowerManager.nativeSetInteractive */
+        public void nativeSetInteractive(boolean enable) {
+            PowerManagerService.nativeSetInteractive(enable);
+        }
+
+        /** Wrapper for PowerManager.nativeSetAutoSuspend */
+        public void nativeSetAutoSuspend(boolean enable) {
+            PowerManagerService.nativeSetAutoSuspend(enable);
+        }
+
+        /** Wrapper for PowerManager.nativeSendPowerHint */
+        public void nativeSendPowerHint(int hintId, int data) {
+            PowerManagerService.nativeSendPowerHint(hintId, data);
+        }
+
+        /** Wrapper for PowerManager.nativeSetFeature */
+        public void nativeSetFeature(int featureId, int data) {
+            PowerManagerService.nativeSetFeature(featureId, data);
+        }
+    }
+
+    @VisibleForTesting
+    static class Injector {
+        Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
+                SuspendBlocker suspendBlocker, WindowManagerPolicy policy) {
+            return new Notifier(looper, context, batteryStats, suspendBlocker, policy);
+        }
+
+        SuspendBlocker createSuspendBlocker(PowerManagerService service, String name) {
+            SuspendBlocker suspendBlocker = service.new SuspendBlockerImpl(name);
+            service.mSuspendBlockers.add(suspendBlocker);
+            return suspendBlocker;
+        }
+
+        BatterySaverPolicy createBatterySaverPolicy(
+                Object lock, Context context, BatterySavingStats batterySavingStats) {
+            return new BatterySaverPolicy(lock, context, batterySavingStats);
+        }
+
+        NativeWrapper createNativeWrapper() {
+            return new NativeWrapper();
+        }
+    }
+
     final Constants mConstants;
 
     private native void nativeInit();
-
     private static native void nativeAcquireSuspendBlocker(String name);
     private static native void nativeReleaseSuspendBlocker(String name);
     private static native void nativeSetInteractive(boolean enable);
@@ -648,8 +716,19 @@
     private static native void nativeSetFeature(int featureId, int data);
 
     public PowerManagerService(Context context) {
+        this(context, new Injector());
+    }
+
+    @VisibleForTesting
+    PowerManagerService(Context context, Injector injector) {
         super(context);
+
         mContext = context;
+        mBinderService = new BinderService();
+        mLocalService = new LocalService();
+        mNativeWrapper = injector.createNativeWrapper();
+        mInjector = injector;
+
         mHandlerThread = new ServiceThread(TAG,
                 Process.THREAD_PRIORITY_DISPLAY, false /*allowIo*/);
         mHandlerThread.start();
@@ -658,57 +737,40 @@
         mAmbientDisplayConfiguration = new AmbientDisplayConfiguration(mContext);
 
         mBatterySavingStats = new BatterySavingStats(mLock);
-        mBatterySaverPolicy = new BatterySaverPolicy(mLock, mContext, mBatterySavingStats);
+        mBatterySaverPolicy =
+                mInjector.createBatterySaverPolicy(mLock, mContext, mBatterySavingStats);
         mBatterySaverController = new BatterySaverController(mLock, mContext,
-                BackgroundThread.get().getLooper(), mBatterySaverPolicy, mBatterySavingStats);
+                BackgroundThread.get().getLooper(), mBatterySaverPolicy,
+                mBatterySavingStats);
         mBatterySaverStateMachine = new BatterySaverStateMachine(
                 mLock, mContext, mBatterySaverController);
 
         synchronized (mLock) {
-            mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks");
-            mDisplaySuspendBlocker = createSuspendBlockerLocked("PowerManagerService.Display");
-            mDisplaySuspendBlocker.acquire();
-            mHoldingDisplaySuspendBlocker = true;
+            mWakeLockSuspendBlocker =
+                    mInjector.createSuspendBlocker(this, "PowerManagerService.WakeLocks");
+            mDisplaySuspendBlocker =
+                    mInjector.createSuspendBlocker(this, "PowerManagerService.Display");
+            if (mDisplaySuspendBlocker != null) {
+                mDisplaySuspendBlocker.acquire();
+                mHoldingDisplaySuspendBlocker = true;
+            }
             mHalAutoSuspendModeEnabled = false;
             mHalInteractiveModeEnabled = true;
 
             mWakefulness = WAKEFULNESS_AWAKE;
-
             sQuiescent = SystemProperties.get(SYSTEM_PROPERTY_QUIESCENT, "0").equals("1");
 
-            nativeInit();
-            nativeSetAutoSuspend(false);
-            nativeSetInteractive(true);
-            nativeSetFeature(POWER_FEATURE_DOUBLE_TAP_TO_WAKE, 0);
+            mNativeWrapper.nativeInit(this);
+            mNativeWrapper.nativeSetAutoSuspend(false);
+            mNativeWrapper.nativeSetInteractive(true);
+            mNativeWrapper.nativeSetFeature(POWER_FEATURE_DOUBLE_TAP_TO_WAKE, 0);
         }
     }
 
-    @VisibleForTesting
-    PowerManagerService(Context context, BatterySaverPolicy batterySaverPolicy) {
-        super(context);
-
-        mContext = context;
-        mHandlerThread = new ServiceThread(TAG,
-                Process.THREAD_PRIORITY_DISPLAY, false /*allowIo*/);
-        mHandlerThread.start();
-        mHandler = new PowerManagerHandler(mHandlerThread.getLooper());
-        mConstants = new Constants(mHandler);
-        mAmbientDisplayConfiguration = new AmbientDisplayConfiguration(mContext);
-        mDisplaySuspendBlocker = null;
-        mWakeLockSuspendBlocker = null;
-
-        mBatterySavingStats = new BatterySavingStats(mLock);
-        mBatterySaverPolicy = batterySaverPolicy;
-        mBatterySaverController = new BatterySaverController(mLock, context,
-                BackgroundThread.getHandler().getLooper(), batterySaverPolicy, mBatterySavingStats);
-        mBatterySaverStateMachine = new BatterySaverStateMachine(
-                mLock, mContext, mBatterySaverController);
-    }
-
     @Override
     public void onStart() {
-        publishBinderService(Context.POWER_SERVICE, new BinderService());
-        publishLocalService(PowerManagerInternal.class, new LocalService());
+        publishBinderService(Context.POWER_SERVICE, mBinderService);
+        publishLocalService(PowerManagerInternal.class, mLocalService);
 
         Watchdog.getInstance().addMonitor(this);
         Watchdog.getInstance().addThread(mHandler);
@@ -752,11 +814,13 @@
             // The notifier runs on the system server's main looper so as not to interfere
             // with the animations and other critical functions of the power manager.
             mBatteryStats = BatteryStatsService.getService();
-            mNotifier = new Notifier(Looper.getMainLooper(), mContext, mBatteryStats,
-                    createSuspendBlockerLocked("PowerManagerService.Broadcasts"), mPolicy);
+            mNotifier = mInjector.createNotifier(Looper.getMainLooper(), mContext, mBatteryStats,
+                    mInjector.createSuspendBlocker(this, "PowerManagerService.Broadcasts"),
+                    mPolicy);
 
             mWirelessChargerDetector = new WirelessChargerDetector(sensorManager,
-                    createSuspendBlockerLocked("PowerManagerService.WirelessChargerDetector"),
+                    mInjector.createSuspendBlocker(
+                            this, "PowerManagerService.WirelessChargerDetector"),
                     mHandler);
             mSettingsObserver = new SettingsObserver(mHandler);
 
@@ -824,7 +888,7 @@
         resolver.registerContentObserver(Settings.Global.getUriFor(
                 Settings.Global.DEVICE_DEMO_MODE),
                 false, mSettingsObserver, UserHandle.USER_SYSTEM);
-        IVrManager vrManager = (IVrManager) getBinderService(Context.VR_SERVICE);
+        IVrManager vrManager = IVrManager.Stub.asInterface(getBinderService(Context.VR_SERVICE));
         if (vrManager != null) {
             try {
                 vrManager.registerListener(mVrStateCallbacks);
@@ -927,7 +991,8 @@
                             UserHandle.USER_CURRENT) != 0;
             if (doubleTapWakeEnabled != mDoubleTapWakeEnabled) {
                 mDoubleTapWakeEnabled = doubleTapWakeEnabled;
-                nativeSetFeature(POWER_FEATURE_DOUBLE_TAP_TO_WAKE, mDoubleTapWakeEnabled ? 1 : 0);
+                mNativeWrapper.nativeSetFeature(
+                        POWER_FEATURE_DOUBLE_TAP_TO_WAKE, mDoubleTapWakeEnabled ? 1 : 0);
             }
         }
 
@@ -1509,6 +1574,11 @@
         }
     }
 
+    @VisibleForTesting
+    int getWakefulness() {
+        return mWakefulness;
+    }
+
     /**
      * Logs the time the device would have spent awake before user activity timeout,
      * had the system not been told the user was inactive.
@@ -2640,7 +2710,7 @@
             mHalAutoSuspendModeEnabled = enable;
             Trace.traceBegin(Trace.TRACE_TAG_POWER, "setHalAutoSuspend(" + enable + ")");
             try {
-                nativeSetAutoSuspend(enable);
+                mNativeWrapper.nativeSetAutoSuspend(enable);
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_POWER);
             }
@@ -2655,7 +2725,7 @@
             mHalInteractiveModeEnabled = enable;
             Trace.traceBegin(Trace.TRACE_TAG_POWER, "setHalInteractive(" + enable + ")");
             try {
-                nativeSetInteractive(enable);
+                mNativeWrapper.nativeSetInteractive(enable);
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_POWER);
             }
@@ -3127,7 +3197,7 @@
                 break;
         }
 
-        nativeSendPowerHint(hintId, data);
+        mNativeWrapper.nativeSendPowerHint(hintId, data);
     }
 
     /**
@@ -3718,12 +3788,6 @@
         proto.flush();
     }
 
-    private SuspendBlocker createSuspendBlockerLocked(String name) {
-        SuspendBlocker suspendBlocker = new SuspendBlockerImpl(name);
-        mSuspendBlockers.add(suspendBlocker);
-        return suspendBlocker;
-    }
-
     private void incrementBootCount() {
         synchronized (mLock) {
             int count;
@@ -4022,7 +4086,7 @@
                     Slog.wtf(TAG, "Suspend blocker \"" + mName
                             + "\" was finalized without being released!");
                     mReferenceCount = 0;
-                    nativeReleaseSuspendBlocker(mName);
+                    mNativeWrapper.nativeReleaseSuspendBlocker(mName);
                     Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, mTraceName, 0);
                 }
             } finally {
@@ -4039,7 +4103,7 @@
                         Slog.d(TAG, "Acquiring suspend blocker \"" + mName + "\".");
                     }
                     Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, mTraceName, 0);
-                    nativeAcquireSuspendBlocker(mName);
+                    mNativeWrapper.nativeAcquireSuspendBlocker(mName);
                 }
             }
         }
@@ -4052,7 +4116,7 @@
                     if (DEBUG_SPEW) {
                         Slog.d(TAG, "Releasing suspend blocker \"" + mName + "\".");
                     }
-                    nativeReleaseSuspendBlocker(mName);
+                    mNativeWrapper.nativeReleaseSuspendBlocker(mName);
                     Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, mTraceName, 0);
                 } else if (mReferenceCount < 0) {
                     Slog.wtf(TAG, "Suspend blocker \"" + mName
@@ -4090,7 +4154,8 @@
         }
     }
 
-    private final class BinderService extends IPowerManager.Stub {
+    @VisibleForTesting
+    final class BinderService extends IPowerManager.Stub {
         @Override
         public void onShellCommand(FileDescriptor in, FileDescriptor out,
                 FileDescriptor err, String[] args, ShellCallback callback,
@@ -4592,6 +4657,16 @@
     }
 
     @VisibleForTesting
+    BinderService getBinderServiceInstance() {
+        return mBinderService;
+    }
+
+    @VisibleForTesting
+    LocalService getLocalServiceInstance() {
+        return mLocalService;
+    }
+
+    @VisibleForTesting
     // lastRebootReasonProperty argument to permit testing
     int getLastShutdownReasonInternal(String lastRebootReasonProperty) {
         String line = SystemProperties.get(lastRebootReasonProperty);
diff --git a/services/core/java/com/android/server/security/VerityUtils.java b/services/core/java/com/android/server/security/VerityUtils.java
index 180f343..9f69702 100644
--- a/services/core/java/com/android/server/security/VerityUtils.java
+++ b/services/core/java/com/android/server/security/VerityUtils.java
@@ -23,11 +23,11 @@
 import android.os.SharedMemory;
 import android.system.ErrnoException;
 import android.system.Os;
+import android.util.Pair;
+import android.util.Slog;
 import android.util.apk.ApkSignatureVerifier;
 import android.util.apk.ByteBufferFactory;
 import android.util.apk.SignatureNotFoundException;
-import android.util.Pair;
-import android.util.Slog;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
@@ -85,7 +85,7 @@
      */
     public static byte[] generateFsverityRootHash(@NonNull String apkPath)
             throws NoSuchAlgorithmException, DigestException, IOException {
-        return ApkSignatureVerifier.generateFsverityRootHash(apkPath);
+        return ApkSignatureVerifier.generateApkVerityRootHash(apkPath);
     }
 
     /**
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 6f9d803..c6e6449 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -32,6 +32,7 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
+import android.hardware.fingerprint.FingerprintManager;
 import android.net.NetworkStats;
 import android.net.wifi.IWifiManager;
 import android.net.wifi.WifiActivityEnergyInfo;
@@ -44,6 +45,8 @@
 import android.os.IStatsCompanionService;
 import android.os.IStatsManager;
 import android.os.IStoraged;
+import android.os.IThermalEventListener;
+import android.os.IThermalService;
 import android.os.Parcelable;
 import android.os.Process;
 import android.os.RemoteException;
@@ -53,6 +56,7 @@
 import android.os.StatsLogEventWrapper;
 import android.os.SynchronousResultReceiver;
 import android.os.SystemClock;
+import android.os.Temperature;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.storage.StorageManager;
@@ -119,7 +123,7 @@
     public static final String CONFIG_DIR = "/data/misc/stats-service";
 
     static final String TAG = "StatsCompanionService";
-    static final boolean DEBUG = false;
+    static final boolean DEBUG = true;
 
     public static final int CODE_DATA_BROADCAST = 1;
     public static final int CODE_SUBSCRIBER_BROADCAST = 1;
@@ -169,6 +173,8 @@
     private KernelUidCpuClusterTimeReader mKernelUidCpuClusterTimeReader =
             new KernelUidCpuClusterTimeReader();
 
+    private static IThermalService sThermalService;
+
     public StatsCompanionService(Context context) {
         super();
         mContext = context;
@@ -213,6 +219,24 @@
         long[] freqs = mKernelUidCpuFreqTimeReader.readFreqs(powerProfile);
         mKernelUidCpuClusterTimeReader.setThrottleInterval(0);
         mKernelUidCpuActiveTimeReader.setThrottleInterval(0);
+
+        // Enable push notifications of throttling from vendor thermal
+        // management subsystem via thermalservice.
+        IBinder b = ServiceManager.getService("thermalservice");
+
+        if (b != null) {
+            sThermalService = IThermalService.Stub.asInterface(b);
+            try {
+                sThermalService.registerThermalEventListener(
+                        new ThermalEventListener());
+                Slog.i(TAG, "register thermal listener successfully");
+            } catch (RemoteException e) {
+                // Should never happen.
+                Slog.e(TAG, "register thermal listener error");
+            }
+        } else {
+            Slog.e(TAG, "cannot find thermalservice, no throttling push notifications");
+        }
     }
 
     @Override
@@ -230,34 +254,38 @@
 
     @Override
     public void sendSubscriberBroadcast(IBinder intentSenderBinder, long configUid, long configKey,
-                                        long subscriptionId, long subscriptionRuleId,
-                                        String[] cookies,
-                                        StatsDimensionsValue dimensionsValue) {
+            long subscriptionId, long subscriptionRuleId, String[] cookies,
+            StatsDimensionsValue dimensionsValue) {
         enforceCallingPermission();
         IntentSender intentSender = new IntentSender(intentSenderBinder);
-        Intent intent = new Intent()
-                .putExtra(StatsManager.EXTRA_STATS_CONFIG_UID, configUid)
-                .putExtra(StatsManager.EXTRA_STATS_CONFIG_KEY, configKey)
-                .putExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_ID, subscriptionId)
-                .putExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_RULE_ID, subscriptionRuleId)
-                .putExtra(StatsManager.EXTRA_STATS_DIMENSIONS_VALUE, dimensionsValue);
+        Intent intent =
+                new Intent()
+                        .putExtra(StatsManager.EXTRA_STATS_CONFIG_UID, configUid)
+                        .putExtra(StatsManager.EXTRA_STATS_CONFIG_KEY, configKey)
+                        .putExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_ID, subscriptionId)
+                        .putExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_RULE_ID, subscriptionRuleId)
+                        .putExtra(StatsManager.EXTRA_STATS_DIMENSIONS_VALUE, dimensionsValue);
 
         ArrayList<String> cookieList = new ArrayList<>(cookies.length);
-        for (String cookie : cookies) { cookieList.add(cookie); }
+        for (String cookie : cookies) {
+            cookieList.add(cookie);
+        }
         intent.putStringArrayListExtra(
                 StatsManager.EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES, cookieList);
 
         if (DEBUG) {
-            Slog.d(TAG, String.format(
-                    "Statsd sendSubscriberBroadcast with params {%d %d %d %d %s %s}",
-                    configUid, configKey, subscriptionId, subscriptionRuleId,
-                    Arrays.toString(cookies), dimensionsValue));
+            Slog.d(TAG,
+                    String.format("Statsd sendSubscriberBroadcast with params {%d %d %d %d %s %s}",
+                            configUid, configKey, subscriptionId, subscriptionRuleId,
+                            Arrays.toString(cookies),
+                            dimensionsValue));
         }
         try {
             intentSender.sendIntent(mContext, CODE_SUBSCRIBER_BROADCAST, intent, null, null);
         } catch (IntentSender.SendIntentException e) {
-            Slog.w(TAG, "Unable to send using IntentSender from uid " + configUid
-                    + "; presumably it had been cancelled.");
+            Slog.w(TAG,
+                    "Unable to send using IntentSender from uid " + configUid
+                            + "; presumably it had been cancelled.");
         }
     }
 
@@ -294,7 +322,7 @@
         // Add in all the apps for every user/profile.
         for (UserInfo profile : users) {
             List<PackageInfo> pi =
-                pm.getInstalledPackagesAsUser(PackageManager.MATCH_KNOWN_PACKAGES, profile.id);
+                    pm.getInstalledPackagesAsUser(PackageManager.MATCH_KNOWN_PACKAGES, profile.id);
             for (int j = 0; j < pi.size(); j++) {
                 if (pi.get(j).applicationInfo != null) {
                     uids.add(pi.get(j).applicationInfo.uid);
@@ -379,8 +407,9 @@
     public final static class PullingAlarmListener implements OnAlarmListener {
         @Override
         public void onAlarm() {
-            if (DEBUG)
+            if (DEBUG) {
                 Slog.d(TAG, "Time to poll something.");
+            }
             synchronized (sStatsdLock) {
                 if (sStatsd == null) {
                     Slog.w(TAG, "Could not access statsd to inform it of pulling alarm firing.");
@@ -399,8 +428,9 @@
     public final static class PeriodicAlarmListener implements OnAlarmListener {
         @Override
         public void onAlarm() {
-            if (DEBUG)
+            if (DEBUG) {
                 Slog.d(TAG, "Time to trigger periodic alarm.");
+            }
             synchronized (sStatsdLock) {
                 if (sStatsd == null) {
                     Slog.w(TAG, "Could not access statsd to inform it of periodic alarm firing.");
@@ -436,7 +466,7 @@
                     return;
                 }
                 try {
-                  sStatsd.informDeviceShutdown();
+                    sStatsd.informDeviceShutdown();
                 } catch (Exception e) {
                     Slog.w(TAG, "Failed to inform statsd of a shutdown event.", e);
                 }
@@ -475,9 +505,11 @@
     @Override // Binder call
     public void setAlarmForSubscriberTriggering(long timestampMs) {
         enforceCallingPermission();
-        if (DEBUG)
-            Slog.d(TAG, "Setting periodic alarm in about " +
-                    (timestampMs - SystemClock.elapsedRealtime()));
+        if (DEBUG) {
+            Slog.d(TAG,
+                    "Setting periodic alarm in about " + (timestampMs
+                            - SystemClock.elapsedRealtime()));
+        }
         final long callingToken = Binder.clearCallingIdentity();
         try {
             // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
@@ -492,8 +524,9 @@
     @Override // Binder call
     public void cancelAlarmForSubscriberTriggering() {
         enforceCallingPermission();
-        if (DEBUG)
+        if (DEBUG) {
             Slog.d(TAG, "Cancelling periodic alarm");
+        }
         final long callingToken = Binder.clearCallingIdentity();
         try {
             mAlarmManager.cancel(mPeriodicAlarmListener);
@@ -523,8 +556,9 @@
     @Override // Binder call
     public void cancelPullingAlarm() {
         enforceCallingPermission();
-        if (DEBUG)
+        if (DEBUG) {
             Slog.d(TAG, "Cancelling pulling alarm");
+        }
         final long callingToken = Binder.clearCallingIdentity();
         try {
             mAlarmManager.cancel(mPullingAlarmListener);
@@ -537,10 +571,11 @@
             int tag, List<StatsLogEventWrapper> ret, NetworkStats stats, boolean withFGBG) {
         int size = stats.size();
         long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+        long wallClockNanos = SystemClock.currentTimeMicro() * 1000L;
         NetworkStats.Entry entry = new NetworkStats.Entry(); // For recycling
         for (int j = 0; j < size; j++) {
             stats.getValues(j, entry);
-            StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tag, withFGBG ? 6 : 5);
+            StatsLogEventWrapper e = new StatsLogEventWrapper(tag, elapsedNanos, wallClockNanos);
             e.writeInt(entry.uid);
             if (withFGBG) {
                 e.writeInt(entry.set);
@@ -616,14 +651,15 @@
         return null;
     }
 
-    private void pullKernelWakelock(int tagId, List<StatsLogEventWrapper> pulledData) {
+    private void pullKernelWakelock(
+            int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
         final KernelWakelockStats wakelockStats =
                 mKernelWakelockReader.readKernelWakelockStats(mTmpWakelockStats);
-        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
         for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) {
             String name = ent.getKey();
             KernelWakelockStats.Entry kws = ent.getValue();
-            StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 4);
+            StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
             e.writeString(name);
             e.writeInt(kws.mCount);
             e.writeInt(kws.mVersion);
@@ -632,7 +668,9 @@
         }
     }
 
-    private void pullWifiBytesTransfer(int tagId, List<StatsLogEventWrapper> pulledData) {
+    private void pullWifiBytesTransfer(
+            int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
         long token = Binder.clearCallingIdentity();
         try {
             // TODO: Consider caching the following call to get BatteryStatsInternal.
@@ -644,7 +682,8 @@
             NetworkStatsFactory nsf = new NetworkStatsFactory();
             // Combine all the metrics per Uid into one record.
             NetworkStats stats =
-                    nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE, null)
+                    nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE,
+                            null)
                             .groupedByUid();
             addNetworkStats(tagId, pulledData, stats, false);
         } catch (java.io.IOException e) {
@@ -654,7 +693,9 @@
         }
     }
 
-    private void pullWifiBytesTransferByFgBg(int tagId, List<StatsLogEventWrapper> pulledData) {
+    private void pullWifiBytesTransferByFgBg(
+            int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
         long token = Binder.clearCallingIdentity();
         try {
             BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
@@ -664,7 +705,8 @@
             }
             NetworkStatsFactory nsf = new NetworkStatsFactory();
             NetworkStats stats = rollupNetworkStatsByFGBG(
-                    nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE, null));
+                    nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE,
+                            null));
             addNetworkStats(tagId, pulledData, stats, true);
         } catch (java.io.IOException e) {
             Slog.e(TAG, "Pulling netstats for wifi bytes w/ fg/bg has error", e);
@@ -673,7 +715,9 @@
         }
     }
 
-    private void pullMobileBytesTransfer(int tagId, List<StatsLogEventWrapper> pulledData) {
+    private void pullMobileBytesTransfer(
+            int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
         long token = Binder.clearCallingIdentity();
         try {
             BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
@@ -684,7 +728,8 @@
             NetworkStatsFactory nsf = new NetworkStatsFactory();
             // Combine all the metrics per Uid into one record.
             NetworkStats stats =
-                    nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE, null)
+                    nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE,
+                            null)
                             .groupedByUid();
             addNetworkStats(tagId, pulledData, stats, false);
         } catch (java.io.IOException e) {
@@ -694,12 +739,14 @@
         }
     }
 
-    private void pullBluetoothBytesTransfer(int tagId, List<StatsLogEventWrapper> pulledData) {
+    private void pullBluetoothBytesTransfer(
+            int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
         BluetoothActivityEnergyInfo info = pullBluetoothData();
-        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
         if (info.getUidTraffic() != null) {
             for (UidTraffic traffic : info.getUidTraffic()) {
-                StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3);
+                StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos,
+                        wallClockNanos);
                 e.writeInt(traffic.getUid());
                 e.writeLong(traffic.getRxBytes());
                 e.writeLong(traffic.getTxBytes());
@@ -708,7 +755,9 @@
         }
     }
 
-    private void pullMobileBytesTransferByFgBg(int tagId, List<StatsLogEventWrapper> pulledData) {
+    private void pullMobileBytesTransferByFgBg(
+            int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
         long token = Binder.clearCallingIdentity();
         try {
             BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
@@ -718,7 +767,8 @@
             }
             NetworkStatsFactory nsf = new NetworkStatsFactory();
             NetworkStats stats = rollupNetworkStatsByFGBG(
-                    nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE, null));
+                    nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE,
+                            null));
             addNetworkStats(tagId, pulledData, stats, true);
         } catch (java.io.IOException e) {
             Slog.e(TAG, "Pulling netstats for mobile bytes w/ fg/bg has error", e);
@@ -727,13 +777,15 @@
         }
     }
 
-    private void pullCpuTimePerFreq(int tagId, List<StatsLogEventWrapper> pulledData) {
-        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+    private void pullCpuTimePerFreq(
+            int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
         for (int cluster = 0; cluster < mKernelCpuSpeedReaders.length; cluster++) {
             long[] clusterTimeMs = mKernelCpuSpeedReaders[cluster].readAbsolute();
             if (clusterTimeMs != null) {
                 for (int speed = clusterTimeMs.length - 1; speed >= 0; --speed) {
-                    StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3);
+                    StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos,
+                            wallClockNanos);
                     e.writeInt(cluster);
                     e.writeInt(speed);
                     e.writeLong(clusterTimeMs[speed]);
@@ -743,10 +795,11 @@
         }
     }
 
-    private void pullKernelUidCpuTime(int tagId, List<StatsLogEventWrapper> pulledData) {
-        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+    private void pullKernelUidCpuTime(
+            int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
         mKernelUidCpuTimeReader.readAbsolute((uid, userTimeUs, systemTimeUs) -> {
-            StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3);
+            StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
             e.writeInt(uid);
             e.writeLong(userTimeUs);
             e.writeLong(systemTimeUs);
@@ -754,12 +807,14 @@
         });
     }
 
-    private void pullKernelUidCpuFreqTime(int tagId, List<StatsLogEventWrapper> pulledData) {
-        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+    private void pullKernelUidCpuFreqTime(
+            int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
         mKernelUidCpuFreqTimeReader.readAbsolute((uid, cpuFreqTimeMs) -> {
             for (int freqIndex = 0; freqIndex < cpuFreqTimeMs.length; ++freqIndex) {
-                if(cpuFreqTimeMs[freqIndex] != 0) {
-                    StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3);
+                if (cpuFreqTimeMs[freqIndex] != 0) {
+                    StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos,
+                            wallClockNanos);
                     e.writeInt(uid);
                     e.writeInt(freqIndex);
                     e.writeLong(cpuFreqTimeMs[freqIndex]);
@@ -769,11 +824,13 @@
         });
     }
 
-    private void pullKernelUidCpuClusterTime(int tagId, List<StatsLogEventWrapper> pulledData) {
-        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+    private void pullKernelUidCpuClusterTime(
+            int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
         mKernelUidCpuClusterTimeReader.readAbsolute((uid, cpuClusterTimesMs) -> {
             for (int i = 0; i < cpuClusterTimesMs.length; i++) {
-                StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3);
+                StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos,
+                        wallClockNanos);
                 e.writeInt(uid);
                 e.writeInt(i);
                 e.writeLong(cpuClusterTimesMs[i]);
@@ -782,17 +839,20 @@
         });
     }
 
-    private void pullKernelUidCpuActiveTime(int tagId, List<StatsLogEventWrapper> pulledData) {
-        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+    private void pullKernelUidCpuActiveTime(
+            int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
         mKernelUidCpuActiveTimeReader.readAbsolute((uid, cpuActiveTimesMs) -> {
-            StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 2);
+            StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
             e.writeInt(uid);
-            e.writeLong((long)cpuActiveTimesMs);
+            e.writeLong((long) cpuActiveTimesMs);
             pulledData.add(e);
         });
     }
 
-    private void pullWifiActivityInfo(int tagId, List<StatsLogEventWrapper> pulledData) {
+    private void pullWifiActivityInfo(
+            int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
         long token = Binder.clearCallingIdentity();
         if (mWifiManager == null) {
             mWifiManager =
@@ -803,7 +863,8 @@
                 SynchronousResultReceiver wifiReceiver = new SynchronousResultReceiver("wifi");
                 mWifiManager.requestActivityInfo(wifiReceiver);
                 final WifiActivityEnergyInfo wifiInfo = awaitControllerInfo(wifiReceiver);
-                StatsLogEventWrapper e = new StatsLogEventWrapper(SystemClock.elapsedRealtimeNanos(), tagId, 6);
+                StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos,
+                        wallClockNanos);
                 e.writeLong(wifiInfo.getTimeStamp());
                 e.writeInt(wifiInfo.getStackState());
                 e.writeLong(wifiInfo.getControllerTxTimeMillis());
@@ -812,14 +873,18 @@
                 e.writeLong(wifiInfo.getControllerEnergyUsed());
                 pulledData.add(e);
             } catch (RemoteException e) {
-                Slog.e(TAG, "Pulling wifiManager for wifi controller activity energy info has error", e);
+                Slog.e(TAG,
+                        "Pulling wifiManager for wifi controller activity energy info has error",
+                        e);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
         }
     }
 
-    private void pullModemActivityInfo(int tagId, List<StatsLogEventWrapper> pulledData) {
+    private void pullModemActivityInfo(
+            int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
         long token = Binder.clearCallingIdentity();
         if (mTelephony == null) {
             mTelephony = TelephonyManager.from(mContext);
@@ -828,7 +893,7 @@
             SynchronousResultReceiver modemReceiver = new SynchronousResultReceiver("telephony");
             mTelephony.requestModemActivityInfo(modemReceiver);
             final ModemActivityInfo modemInfo = awaitControllerInfo(modemReceiver);
-            StatsLogEventWrapper e = new StatsLogEventWrapper(SystemClock.elapsedRealtimeNanos(), tagId, 10);
+            StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
             e.writeLong(modemInfo.getTimestamp());
             e.writeLong(modemInfo.getSleepTimeMillis());
             e.writeLong(modemInfo.getIdleTimeMillis());
@@ -843,9 +908,11 @@
         }
     }
 
-    private void pullBluetoothActivityInfo(int tagId, List<StatsLogEventWrapper> pulledData) {
+    private void pullBluetoothActivityInfo(
+            int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
         BluetoothActivityEnergyInfo info = pullBluetoothData();
-        StatsLogEventWrapper e = new StatsLogEventWrapper(SystemClock.elapsedRealtimeNanos(), tagId, 6);
+        StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
         e.writeLong(info.getTimeStamp());
         e.writeInt(info.getBluetoothStackState());
         e.writeLong(info.getControllerTxTimeMillis());
@@ -858,7 +925,8 @@
     private synchronized BluetoothActivityEnergyInfo pullBluetoothData() {
         final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
         if (adapter != null) {
-            SynchronousResultReceiver bluetoothReceiver = new SynchronousResultReceiver("bluetooth");
+            SynchronousResultReceiver bluetoothReceiver = new SynchronousResultReceiver(
+                    "bluetooth");
             adapter.requestControllerActivityEnergyInfo(bluetoothReceiver);
             return awaitControllerInfo(bluetoothReceiver);
         } else {
@@ -867,25 +935,29 @@
         }
     }
 
-    private void pullSystemElapsedRealtime(int tagId, List<StatsLogEventWrapper> pulledData) {
-        StatsLogEventWrapper e = new StatsLogEventWrapper(SystemClock.elapsedRealtimeNanos(), tagId, 1);
+    private void pullSystemElapsedRealtime(
+            int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
+        StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
         e.writeLong(SystemClock.elapsedRealtime());
         pulledData.add(e);
     }
 
-    private void pullSystemUpTime(int tagId, List<StatsLogEventWrapper> pulledData) {
-        StatsLogEventWrapper e = new StatsLogEventWrapper(SystemClock.elapsedRealtimeNanos(), tagId, 1);
+    private void pullSystemUpTime(int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
+        StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
         e.writeLong(SystemClock.uptimeMillis());
         pulledData.add(e);
     }
 
-    private void pullProcessMemoryState(int tagId, List<StatsLogEventWrapper> pulledData) {
+    private void pullProcessMemoryState(
+            int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
         List<ProcessMemoryState> processMemoryStates =
-                LocalServices.getService(ActivityManagerInternal.class)
-                        .getMemoryStateForProcesses();
-        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+                LocalServices.getService(
+                        ActivityManagerInternal.class).getMemoryStateForProcesses();
         for (ProcessMemoryState processMemoryState : processMemoryStates) {
-            StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 8 /* fields */);
+            StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
             e.writeInt(processMemoryState.uid);
             e.writeString(processMemoryState.processName);
             e.writeInt(processMemoryState.oomScore);
@@ -894,11 +966,14 @@
             e.writeLong(processMemoryState.rssInBytes);
             e.writeLong(processMemoryState.cacheInBytes);
             e.writeLong(processMemoryState.swapInBytes);
+            e.writeLong(processMemoryState.rssHighWatermarkInBytes);
             pulledData.add(e);
         }
     }
 
-    private void pullBinderCallsStats(int tagId, List<StatsLogEventWrapper> pulledData) {
+    private void pullBinderCallsStats(
+            int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
         BinderCallsStatsService.Internal binderStats =
                 LocalServices.getService(BinderCallsStatsService.Internal.class);
         if (binderStats == null) {
@@ -906,9 +981,9 @@
         }
 
         List<ExportedCallStat> callStats = binderStats.getExportedCallStats();
-        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+        binderStats.reset();
         for (ExportedCallStat callStat : callStats) {
-            StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 13 /* fields */);
+            StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
             e.writeInt(callStat.uid);
             e.writeString(callStat.className);
             e.writeString(callStat.methodName);
@@ -926,7 +1001,9 @@
         }
     }
 
-    private void pullBinderCallsStatsExceptions(int tagId, List<StatsLogEventWrapper> pulledData) {
+    private void pullBinderCallsStatsExceptions(
+            int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
         BinderCallsStatsService.Internal binderStats =
                 LocalServices.getService(BinderCallsStatsService.Internal.class);
         if (binderStats == null) {
@@ -934,26 +1011,28 @@
         }
 
         ArrayMap<String, Integer> exceptionStats = binderStats.getExportedExceptionStats();
-        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+        // TODO: decouple binder calls exceptions with the rest of the binder calls data so that we
+        // can reset the exception stats.
         for (Entry<String, Integer> entry : exceptionStats.entrySet()) {
-            StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 2 /* fields */);
+            StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
             e.writeString(entry.getKey());
             e.writeInt(entry.getValue());
             pulledData.add(e);
         }
     }
 
-    private void pullLooperStats(int tagId, List<StatsLogEventWrapper> pulledData) {
+    private void pullLooperStats(int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
         LooperStats looperStats = LocalServices.getService(LooperStats.class);
         if (looperStats == null) {
             return;
         }
 
         List<LooperStats.ExportedEntry> entries = looperStats.getEntries();
-        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+        looperStats.reset();
         for (LooperStats.ExportedEntry entry : entries) {
-            StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 9 /* fields */);
-            e.writeLong(0); // uid collection not implemented yet
+            StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
+            e.writeInt(entry.workSourceUid);
             e.writeString(entry.handlerClassName);
             e.writeString(entry.threadName);
             e.writeString(entry.messageName);
@@ -962,11 +1041,13 @@
             e.writeLong(entry.recordedMessageCount);
             e.writeLong(entry.totalLatencyMicros);
             e.writeLong(entry.cpuUsageMicros);
+            e.writeBoolean(entry.isInteractive);
             pulledData.add(e);
         }
     }
 
-    private void pullDiskStats(int tagId, List<StatsLogEventWrapper> pulledData) {
+    private void pullDiskStats(int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
         // Run a quick-and-dirty performance test: write 512 bytes
         byte[] junk = new byte[512];
         for (int i = 0; i < junk.length; i++) junk[i] = (byte) i;  // Write nonzero bytes
@@ -1013,41 +1094,40 @@
         }
 
         // Add info pulledData.
-        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
-        StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+        StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
         e.writeLong(latency);
         e.writeBoolean(fileBased);
         e.writeInt(writeSpeed);
         pulledData.add(e);
     }
 
-    private void pullDirectoryUsage(int tagId, List<StatsLogEventWrapper> pulledData) {
-        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+    private void pullDirectoryUsage(int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
         StatFs statFsData = new StatFs(Environment.getDataDirectory().getAbsolutePath());
         StatFs statFsSystem = new StatFs(Environment.getRootDirectory().getAbsolutePath());
         StatFs statFsCache = new StatFs(Environment.getDownloadCacheDirectory().getAbsolutePath());
 
-        StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+        StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
         e.writeInt(StatsLog.DIRECTORY_USAGE__DIRECTORY__DATA);
         e.writeLong(statFsData.getAvailableBytes());
         e.writeLong(statFsData.getTotalBytes());
         pulledData.add(e);
 
-        e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+        e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
         e.writeInt(StatsLog.DIRECTORY_USAGE__DIRECTORY__CACHE);
         e.writeLong(statFsCache.getAvailableBytes());
         e.writeLong(statFsCache.getTotalBytes());
         pulledData.add(e);
 
-        e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+        e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
         e.writeInt(StatsLog.DIRECTORY_USAGE__DIRECTORY__SYSTEM);
         e.writeLong(statFsSystem.getAvailableBytes());
         e.writeLong(statFsSystem.getTotalBytes());
         pulledData.add(e);
     }
 
-    private void pullAppSize(int tagId, List<StatsLogEventWrapper> pulledData) {
-        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+    private void pullAppSize(int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
         try {
             String jsonStr = IoUtils.readFileAsString(DiskStatsLoggingService.DUMPSYS_CACHE_PATH);
             JSONObject json = new JSONObject(jsonStr);
@@ -1065,7 +1145,7 @@
             }
             for (int i = 0; i < length; i++) {
                 StatsLogEventWrapper e =
-                        new StatsLogEventWrapper(elapsedNanos, tagId, 5 /* fields */);
+                        new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
                 e.writeString(pkg_names.getString(i));
                 e.writeLong(app_sizes.optLong(i, -1L));
                 e.writeLong(app_data_sizes.optLong(i, -1L));
@@ -1078,62 +1158,62 @@
         }
     }
 
-    private void pullCategorySize(int tagId, List<StatsLogEventWrapper> pulledData) {
-        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+    private void pullCategorySize(int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
         try {
             String jsonStr = IoUtils.readFileAsString(DiskStatsLoggingService.DUMPSYS_CACHE_PATH);
             JSONObject json = new JSONObject(jsonStr);
             long cacheTime = json.optLong(DiskStatsFileLogger.LAST_QUERY_TIMESTAMP_KEY, -1L);
 
-            StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+            StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
             e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__APP_SIZE);
             e.writeLong(json.optLong(DiskStatsFileLogger.APP_SIZE_AGG_KEY, -1L));
             e.writeLong(cacheTime);
             pulledData.add(e);
 
-            e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+            e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
             e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__APP_DATA_SIZE);
             e.writeLong(json.optLong(DiskStatsFileLogger.APP_DATA_SIZE_AGG_KEY, -1L));
             e.writeLong(cacheTime);
             pulledData.add(e);
 
-            e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+            e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
             e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__APP_CACHE_SIZE);
             e.writeLong(json.optLong(DiskStatsFileLogger.APP_CACHE_AGG_KEY, -1L));
             e.writeLong(cacheTime);
             pulledData.add(e);
 
-            e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+            e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
             e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__PHOTOS);
             e.writeLong(json.optLong(DiskStatsFileLogger.PHOTOS_KEY, -1L));
             e.writeLong(cacheTime);
             pulledData.add(e);
 
-            e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+            e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
             e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__VIDEOS);
             e.writeLong(json.optLong(DiskStatsFileLogger.VIDEOS_KEY, -1L));
             e.writeLong(cacheTime);
             pulledData.add(e);
 
-            e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+            e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
             e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__AUDIO);
             e.writeLong(json.optLong(DiskStatsFileLogger.AUDIO_KEY, -1L));
             e.writeLong(cacheTime);
             pulledData.add(e);
 
-            e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+            e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
             e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__DOWNLOADS);
             e.writeLong(json.optLong(DiskStatsFileLogger.DOWNLOADS_KEY, -1L));
             e.writeLong(cacheTime);
             pulledData.add(e);
 
-            e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+            e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
             e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__SYSTEM);
             e.writeLong(json.optLong(DiskStatsFileLogger.SYSTEM_KEY, -1L));
             e.writeLong(cacheTime);
             pulledData.add(e);
 
-            e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+            e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
             e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__OTHER);
             e.writeLong(json.optLong(DiskStatsFileLogger.MISC_KEY, -1L));
             e.writeLong(cacheTime);
@@ -1143,110 +1223,139 @@
         }
     }
 
+    private void pullNumFingerprints(int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
+        FingerprintManager fingerprintManager = mContext.getSystemService(FingerprintManager.class);
+        if (fingerprintManager == null) {
+            return;
+        }
+        UserManager userManager = mContext.getSystemService(UserManager.class);
+        if (userManager == null) {
+            return;
+        }
+        final long token = Binder.clearCallingIdentity();
+        for (UserInfo user : userManager.getUsers()) {
+            final int userId = user.getUserHandle().getIdentifier();
+            final int numFingerprints = fingerprintManager.getEnrolledFingerprints(userId).size();
+            StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
+            e.writeInt(userId);
+            e.writeInt(numFingerprints);
+            pulledData.add(e);
+        }
+        Binder.restoreCallingIdentity(token);
+    }
+
     /**
      * Pulls various data.
      */
     @Override // Binder call
     public StatsLogEventWrapper[] pullData(int tagId) {
         enforceCallingPermission();
-        if (DEBUG)
+        if (DEBUG) {
             Slog.d(TAG, "Pulling " + tagId);
+        }
         List<StatsLogEventWrapper> ret = new ArrayList<>();
+        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+        long wallClockNanos = SystemClock.currentTimeMicro() * 1000L;
         switch (tagId) {
             case StatsLog.WIFI_BYTES_TRANSFER: {
-                pullWifiBytesTransfer(tagId, ret);
+                pullWifiBytesTransfer(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
             case StatsLog.MOBILE_BYTES_TRANSFER: {
-                pullMobileBytesTransfer(tagId, ret);
+                pullMobileBytesTransfer(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
             case StatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG: {
-                pullWifiBytesTransferByFgBg(tagId, ret);
+                pullWifiBytesTransferByFgBg(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
             case StatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG: {
-                pullMobileBytesTransferByFgBg(tagId, ret);
+                pullMobileBytesTransferByFgBg(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
             case StatsLog.BLUETOOTH_BYTES_TRANSFER: {
-                pullBluetoothBytesTransfer(tagId, ret);
+                pullBluetoothBytesTransfer(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
             case StatsLog.KERNEL_WAKELOCK: {
-                pullKernelWakelock(tagId, ret);
+                pullKernelWakelock(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
             case StatsLog.CPU_TIME_PER_FREQ: {
-                pullCpuTimePerFreq(tagId, ret);
+                pullCpuTimePerFreq(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
             case StatsLog.CPU_TIME_PER_UID: {
-                pullKernelUidCpuTime(tagId, ret);
+                pullKernelUidCpuTime(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
             case StatsLog.CPU_TIME_PER_UID_FREQ: {
-                pullKernelUidCpuFreqTime(tagId, ret);
+                pullKernelUidCpuFreqTime(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
             case StatsLog.CPU_CLUSTER_TIME: {
-                pullKernelUidCpuClusterTime(tagId, ret);
+                pullKernelUidCpuClusterTime(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
             case StatsLog.CPU_ACTIVE_TIME: {
-                pullKernelUidCpuActiveTime(tagId, ret);
+                pullKernelUidCpuActiveTime(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
             case StatsLog.WIFI_ACTIVITY_INFO: {
-                pullWifiActivityInfo(tagId, ret);
+                pullWifiActivityInfo(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
             case StatsLog.MODEM_ACTIVITY_INFO: {
-                pullModemActivityInfo(tagId, ret);
+                pullModemActivityInfo(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
             case StatsLog.BLUETOOTH_ACTIVITY_INFO: {
-                pullBluetoothActivityInfo(tagId, ret);
+                pullBluetoothActivityInfo(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
             case StatsLog.SYSTEM_UPTIME: {
-                pullSystemUpTime(tagId, ret);
+                pullSystemUpTime(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
             case StatsLog.SYSTEM_ELAPSED_REALTIME: {
-                pullSystemElapsedRealtime(tagId, ret);
+                pullSystemElapsedRealtime(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
             case StatsLog.PROCESS_MEMORY_STATE: {
-                pullProcessMemoryState(tagId, ret);
+                pullProcessMemoryState(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
             case StatsLog.BINDER_CALLS: {
-                pullBinderCallsStats(tagId, ret);
+                pullBinderCallsStats(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
             case StatsLog.BINDER_CALLS_EXCEPTIONS: {
-                pullBinderCallsStatsExceptions(tagId, ret);
+                pullBinderCallsStatsExceptions(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
             case StatsLog.LOOPER_STATS: {
-                pullLooperStats(tagId, ret);
+                pullLooperStats(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
             case StatsLog.DISK_STATS: {
-                pullDiskStats(tagId, ret);
+                pullDiskStats(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
             case StatsLog.DIRECTORY_USAGE: {
-                pullDirectoryUsage(tagId, ret);
+                pullDirectoryUsage(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
             case StatsLog.APP_SIZE: {
-                pullAppSize(tagId, ret);
+                pullAppSize(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
             case StatsLog.CATEGORY_SIZE: {
-                pullCategorySize(tagId, ret);
+                pullCategorySize(tagId, elapsedNanos, wallClockNanos, ret);
+                break;
+            }
+            case StatsLog.NUM_FINGERPRINTS: {
+                pullNumFingerprints(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
             default:
@@ -1456,4 +1565,12 @@
         }
     }
 
+    // Thermal event received from vendor thermal management subsystem
+    private static final class ThermalEventListener extends IThermalEventListener.Stub {
+        @Override
+        public void notifyThrottling(boolean isThrottling, Temperature temp) {
+            StatsLog.write(StatsLog.THERMAL_THROTTLING, temp.getType(),
+                    isThrottling ? 1 : 0, temp.getValue());
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 14294ec..79eab6b 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -565,10 +565,12 @@
     }
 
     @Override
-    public void showBiometricDialog(Bundle bundle, IBiometricPromptReceiver receiver, int type) {
+    public void showBiometricDialog(Bundle bundle, IBiometricPromptReceiver receiver, int type,
+            boolean requireConfirmation) {
+        enforceBiometricDialog();
         if (mBar != null) {
             try {
-                mBar.showBiometricDialog(bundle, receiver, type);
+                mBar.showBiometricDialog(bundle, receiver, type, requireConfirmation);
             } catch (RemoteException ex) {
             }
         }
@@ -576,6 +578,7 @@
 
     @Override
     public void onBiometricAuthenticated() {
+        enforceBiometricDialog();
         if (mBar != null) {
             try {
                 mBar.onBiometricAuthenticated();
@@ -586,6 +589,7 @@
 
     @Override
     public void onBiometricHelp(String message) {
+        enforceBiometricDialog();
         if (mBar != null) {
             try {
                 mBar.onBiometricHelp(message);
@@ -596,6 +600,7 @@
 
     @Override
     public void onBiometricError(String error) {
+        enforceBiometricDialog();
         if (mBar != null) {
             try {
                 mBar.onBiometricError(error);
@@ -606,6 +611,7 @@
 
     @Override
     public void hideBiometricDialog() {
+        enforceBiometricDialog();
         if (mBar != null) {
             try {
                 mBar.hideBiometricDialog();
@@ -866,6 +872,12 @@
                 "StatusBarManagerService");
     }
 
+    private void enforceBiometricDialog() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_BIOMETRIC_DIALOG,
+                "StatusBarManagerService");
+    }
+
     // ================================================================================
     // Callbacks from the status bar service.
     // ================================================================================
diff --git a/services/core/java/com/android/server/telecom/TelecomLoaderService.java b/services/core/java/com/android/server/telecom/TelecomLoaderService.java
index 6c5452a..7a3f030 100644
--- a/services/core/java/com/android/server/telecom/TelecomLoaderService.java
+++ b/services/core/java/com/android/server/telecom/TelecomLoaderService.java
@@ -22,7 +22,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
-import android.content.pm.PackageManagerInternal;
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Handler;
@@ -39,12 +38,13 @@
 import android.util.IntArray;
 import android.util.Slog;
 
-import android.util.SparseBooleanArray;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.telephony.SmsApplication;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.pm.UserManagerService;
+import com.android.server.pm.permission.DefaultPermissionGrantPolicy;
+import com.android.server.pm.permission.PermissionManagerInternal;
 
 /**
  * Starts the telecom component by binding to its ITelecomService implementation. Telecom is setup
@@ -72,8 +72,8 @@
                 synchronized (mLock) {
                     if (mDefaultSmsAppRequests != null || mDefaultDialerAppRequests != null
                             || mDefaultSimCallManagerRequests != null) {
-                        final PackageManagerInternal packageManagerInternal = LocalServices
-                                .getService(PackageManagerInternal.class);
+                        final DefaultPermissionGrantPolicy permissionPolicy =
+                                getDefaultPermissionGrantPolicy();
 
                         if (mDefaultSmsAppRequests != null) {
                             ComponentName smsComponent = SmsApplication.getDefaultSmsApplication(
@@ -83,7 +83,7 @@
                                 for (int i = requestCount - 1; i >= 0; i--) {
                                     final int userid = mDefaultSmsAppRequests.get(i);
                                     mDefaultSmsAppRequests.remove(i);
-                                    packageManagerInternal.grantDefaultPermissionsToDefaultSmsApp(
+                                    permissionPolicy.grantDefaultPermissionsToDefaultSmsApp(
                                             smsComponent.getPackageName(), userid);
                                 }
                             }
@@ -97,7 +97,7 @@
                                 for (int i = requestCount - 1; i >= 0; i--) {
                                     final int userId = mDefaultDialerAppRequests.get(i);
                                     mDefaultDialerAppRequests.remove(i);
-                                    packageManagerInternal.grantDefaultPermissionsToDefaultDialerApp(
+                                    permissionPolicy.grantDefaultPermissionsToDefaultDialerApp(
                                             packageName, userId);
                                 }
                             }
@@ -113,7 +113,7 @@
                                 for (int i = requestCount - 1; i >= 0; i--) {
                                     final int userId = mDefaultSimCallManagerRequests.get(i);
                                     mDefaultSimCallManagerRequests.remove(i);
-                                    packageManagerInternal
+                                    permissionPolicy
                                             .grantDefaultPermissionsToDefaultSimCallManager(
                                                     packageName, userId);
                                 }
@@ -132,6 +132,11 @@
         }
     }
 
+    private DefaultPermissionGrantPolicy getDefaultPermissionGrantPolicy() {
+        return LocalServices.getService(PermissionManagerInternal.class)
+                .getDefaultPermissionGrantPolicy();
+    }
+
     private static final ComponentName SERVICE_COMPONENT = new ComponentName(
             "com.android.server.telecom",
             "com.android.server.telecom.components.TelecomService");
@@ -196,82 +201,68 @@
 
 
     private void registerDefaultAppProviders() {
-        final PackageManagerInternal packageManagerInternal = LocalServices.getService(
-                PackageManagerInternal.class);
+        final DefaultPermissionGrantPolicy permissionPolicy = getDefaultPermissionGrantPolicy();
 
-        // Set a callback for the package manager to query the default sms app.
-        packageManagerInternal.setSmsAppPackagesProvider(
-                new PackageManagerInternal.PackagesProvider() {
-            @Override
-            public String[] getPackages(int userId) {
-                synchronized (mLock) {
-                    if (mServiceConnection == null) {
-                        if (mDefaultSmsAppRequests == null) {
-                            mDefaultSmsAppRequests = new IntArray();
-                        }
-                        mDefaultSmsAppRequests.add(userId);
-                        return null;
+        // Set a callback for the permission grant policy to query the default sms app.
+        permissionPolicy.setSmsAppPackagesProvider(userId -> {
+            synchronized (mLock) {
+                if (mServiceConnection == null) {
+                    if (mDefaultSmsAppRequests == null) {
+                        mDefaultSmsAppRequests = new IntArray();
                     }
+                    mDefaultSmsAppRequests.add(userId);
+                    return null;
                 }
-                ComponentName smsComponent = SmsApplication.getDefaultSmsApplication(
-                        mContext, true);
-                if (smsComponent != null) {
-                    return new String[]{smsComponent.getPackageName()};
-                }
-                return null;
             }
+            ComponentName smsComponent = SmsApplication.getDefaultSmsApplication(
+                    mContext, true);
+            if (smsComponent != null) {
+                return new String[]{smsComponent.getPackageName()};
+            }
+            return null;
         });
 
-        // Set a callback for the package manager to query the default dialer app.
-        packageManagerInternal.setDialerAppPackagesProvider(
-                new PackageManagerInternal.PackagesProvider() {
-            @Override
-            public String[] getPackages(int userId) {
-                synchronized (mLock) {
-                    if (mServiceConnection == null) {
-                        if (mDefaultDialerAppRequests == null) {
-                            mDefaultDialerAppRequests = new IntArray();
-                        }
-                        mDefaultDialerAppRequests.add(userId);
-                        return null;
+        // Set a callback for the permission grant policy to query the default dialer app.
+        permissionPolicy.setDialerAppPackagesProvider(userId -> {
+            synchronized (mLock) {
+                if (mServiceConnection == null) {
+                    if (mDefaultDialerAppRequests == null) {
+                        mDefaultDialerAppRequests = new IntArray();
                     }
+                    mDefaultDialerAppRequests.add(userId);
+                    return null;
                 }
-                String packageName = DefaultDialerManager.getDefaultDialerApplication(mContext);
-                if (packageName != null) {
-                    return new String[]{packageName};
-                }
-                return null;
             }
+            String packageName = DefaultDialerManager.getDefaultDialerApplication(mContext);
+            if (packageName != null) {
+                return new String[]{packageName};
+            }
+            return null;
         });
 
-        // Set a callback for the package manager to query the default sim call manager.
-        packageManagerInternal.setSimCallManagerPackagesProvider(
-                new PackageManagerInternal.PackagesProvider() {
-            @Override
-            public String[] getPackages(int userId) {
-                synchronized (mLock) {
-                    if (mServiceConnection == null) {
-                        if (mDefaultSimCallManagerRequests == null) {
-                            mDefaultSimCallManagerRequests = new IntArray();
-                        }
-                        mDefaultSimCallManagerRequests.add(userId);
-                        return null;
+        // Set a callback for the permission grant policy to query the default sim call manager.
+        permissionPolicy.setSimCallManagerPackagesProvider(userId -> {
+            synchronized (mLock) {
+                if (mServiceConnection == null) {
+                    if (mDefaultSimCallManagerRequests == null) {
+                        mDefaultSimCallManagerRequests = new IntArray();
                     }
+                    mDefaultSimCallManagerRequests.add(userId);
+                    return null;
                 }
-                TelecomManager telecomManager =
+            }
+            TelecomManager telecomManager =
                     (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
-                PhoneAccountHandle phoneAccount = telecomManager.getSimCallManager(userId);
-                if (phoneAccount != null) {
-                    return new String[]{phoneAccount.getComponentName().getPackageName()};
-                }
-                return null;
+            PhoneAccountHandle phoneAccount = telecomManager.getSimCallManager(userId);
+            if (phoneAccount != null) {
+                return new String[]{phoneAccount.getComponentName().getPackageName()};
             }
+            return null;
         });
     }
 
     private void registerDefaultAppNotifier() {
-        final PackageManagerInternal packageManagerInternal = LocalServices.getService(
-                PackageManagerInternal.class);
+        final DefaultPermissionGrantPolicy permissionPolicy = getDefaultPermissionGrantPolicy();
 
         // Notify the package manager on default app changes
         final Uri defaultSmsAppUri = Settings.Secure.getUriFor(
@@ -287,17 +278,17 @@
                     ComponentName smsComponent = SmsApplication.getDefaultSmsApplication(
                             mContext, true);
                     if (smsComponent != null) {
-                        packageManagerInternal.grantDefaultPermissionsToDefaultSmsApp(
+                        permissionPolicy.grantDefaultPermissionsToDefaultSmsApp(
                                 smsComponent.getPackageName(), userId);
                     }
                 } else if (defaultDialerAppUri.equals(uri)) {
                     String packageName = DefaultDialerManager.getDefaultDialerApplication(
                             mContext);
                     if (packageName != null) {
-                        packageManagerInternal.grantDefaultPermissionsToDefaultDialerApp(
+                        permissionPolicy.grantDefaultPermissionsToDefaultDialerApp(
                                 packageName, userId);
                     }
-                    updateSimCallManagerPermissions(packageManagerInternal, userId);
+                    updateSimCallManagerPermissions(permissionPolicy, userId);
                 }
             }
         };
@@ -310,14 +301,12 @@
 
 
     private void registerCarrierConfigChangedReceiver() {
-        final PackageManagerInternal packageManagerInternal = LocalServices.getService(
-                PackageManagerInternal.class);
         BroadcastReceiver receiver = new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
                 if (intent.getAction().equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) {
                     for (int userId : UserManagerService.getInstance().getUserIds()) {
-                        updateSimCallManagerPermissions(packageManagerInternal, userId);
+                        updateSimCallManagerPermissions(getDefaultPermissionGrantPolicy(), userId);
                     }
                 }
             }
@@ -327,15 +316,15 @@
             new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED), null, null);
     }
 
-    private void updateSimCallManagerPermissions(PackageManagerInternal packageManagerInternal,
-            int userId) {
+    private void updateSimCallManagerPermissions(
+            DefaultPermissionGrantPolicy permissionGrantPolicy, int userId) {
         TelecomManager telecomManager =
             (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
         PhoneAccountHandle phoneAccount = telecomManager.getSimCallManager(userId);
         if (phoneAccount != null) {
             Slog.i(TAG, "updating sim call manager permissions for userId:" + userId);
             String packageName = phoneAccount.getComponentName().getPackageName();
-            packageManagerInternal.grantDefaultPermissionsToDefaultSimCallManager(
+            permissionGrantPolicy.grantDefaultPermissionsToDefaultSimCallManager(
                 packageName, userId);
         }
     }
diff --git a/core/java/com/android/internal/textservice/LazyIntToIntMap.java b/services/core/java/com/android/server/textservices/LazyIntToIntMap.java
similarity index 91%
rename from core/java/com/android/internal/textservice/LazyIntToIntMap.java
rename to services/core/java/com/android/server/textservices/LazyIntToIntMap.java
index ca9936c..2e7f2a9 100644
--- a/core/java/com/android/internal/textservice/LazyIntToIntMap.java
+++ b/services/core/java/com/android/server/textservices/LazyIntToIntMap.java
@@ -14,21 +14,18 @@
  * limitations under the License.
  */
 
-package com.android.internal.textservice;
+package com.android.server.textservices;
 
 import android.annotation.NonNull;
 import android.util.SparseIntArray;
 
-import com.android.internal.annotations.VisibleForTesting;
-
 import java.util.function.IntUnaryOperator;
 
 /**
  * Simple int-to-int key-value-store that is to be lazily initialized with the given
  * {@link IntUnaryOperator}.
  */
-@VisibleForTesting
-public final class LazyIntToIntMap {
+final class LazyIntToIntMap {
 
     private final SparseIntArray mMap = new SparseIntArray();
 
diff --git a/services/core/java/com/android/server/textservices/LocaleUtils.java b/services/core/java/com/android/server/textservices/LocaleUtils.java
new file mode 100644
index 0000000..89d8c1e
--- /dev/null
+++ b/services/core/java/com/android/server/textservices/LocaleUtils.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.textservices;
+
+import android.annotation.Nullable;
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+import java.util.Locale;
+
+/**
+ * Provides {@code Locale} related utility methods for {@link TextServicesManagerService}.
+ * <p>This class is intentionally package-private.  Utility methods here are tightly coupled with
+ * implementation details in {@link TextServicesManagerService}.  Hence this class is not suitable
+ * for other components to directly use.</p>
+ */
+final class LocaleUtils {
+    /**
+     * Returns a list of {@link Locale} in the order of appropriateness for the default spell
+     * checker service.
+     *
+     * <p>If the system language is English, and the region is also explicitly specified in the
+     * system locale, the following fallback order will be applied.</p>
+     * <ul>
+     * <li>(system-locale-language, system-locale-region, system-locale-variant) (if exists)</li>
+     * <li>(system-locale-language, system-locale-region)</li>
+     * <li>("en", "US")</li>
+     * <li>("en", "GB")</li>
+     * <li>("en")</li>
+     * </ul>
+     *
+     * <p>If the system language is English, but no region is specified in the system locale,
+     * the following fallback order will be applied.</p>
+     * <ul>
+     * <li>("en")</li>
+     * <li>("en", "US")</li>
+     * <li>("en", "GB")</li>
+     * </ul>
+     *
+     * <p>If the system language is not English, the following fallback order will be applied.</p>
+     * <ul>
+     * <li>(system-locale-language, system-locale-region, system-locale-variant) (if exists)</li>
+     * <li>(system-locale-language, system-locale-region) (if exists)</li>
+     * <li>(system-locale-language) (if exists)</li>
+     * <li>("en", "US")</li>
+     * <li>("en", "GB")</li>
+     * <li>("en")</li>
+     * </ul>
+     *
+     * @param systemLocale the current system locale to be taken into consideration.
+     * @return a list of {@link Locale}. The first one is considered to be most appropriate.
+     */
+    public static ArrayList<Locale> getSuitableLocalesForSpellChecker(
+            @Nullable final Locale systemLocale) {
+        final Locale systemLocaleLanguageCountryVariant;
+        final Locale systemLocaleLanguageCountry;
+        final Locale systemLocaleLanguage;
+        if (systemLocale != null) {
+            final String language = systemLocale.getLanguage();
+            final boolean hasLanguage = !TextUtils.isEmpty(language);
+            final String country = systemLocale.getCountry();
+            final boolean hasCountry = !TextUtils.isEmpty(country);
+            final String variant = systemLocale.getVariant();
+            final boolean hasVariant = !TextUtils.isEmpty(variant);
+            if (hasLanguage && hasCountry && hasVariant) {
+                systemLocaleLanguageCountryVariant = new Locale(language, country, variant);
+            } else {
+                systemLocaleLanguageCountryVariant = null;
+            }
+            if (hasLanguage && hasCountry) {
+                systemLocaleLanguageCountry = new Locale(language, country);
+            } else {
+                systemLocaleLanguageCountry = null;
+            }
+            if (hasLanguage) {
+                systemLocaleLanguage = new Locale(language);
+            } else {
+                systemLocaleLanguage = null;
+            }
+        } else {
+            systemLocaleLanguageCountryVariant = null;
+            systemLocaleLanguageCountry = null;
+            systemLocaleLanguage = null;
+        }
+
+        final ArrayList<Locale> locales = new ArrayList<>();
+        if (systemLocaleLanguageCountryVariant != null) {
+            locales.add(systemLocaleLanguageCountryVariant);
+        }
+
+        if (Locale.ENGLISH.equals(systemLocaleLanguage)) {
+            if (systemLocaleLanguageCountry != null) {
+                // If the system language is English, and the region is also explicitly specified,
+                // following fallback order will be applied.
+                // - systemLocaleLanguageCountry [if systemLocaleLanguageCountry is non-null]
+                // - en_US [if systemLocaleLanguageCountry is non-null and not en_US]
+                // - en_GB [if systemLocaleLanguageCountry is non-null and not en_GB]
+                // - en
+                if (systemLocaleLanguageCountry != null) {
+                    locales.add(systemLocaleLanguageCountry);
+                }
+                if (!Locale.US.equals(systemLocaleLanguageCountry)) {
+                    locales.add(Locale.US);
+                }
+                if (!Locale.UK.equals(systemLocaleLanguageCountry)) {
+                    locales.add(Locale.UK);
+                }
+                locales.add(Locale.ENGLISH);
+            } else {
+                // If the system language is English, but no region is specified, following
+                // fallback order will be applied.
+                // - en
+                // - en_US
+                // - en_GB
+                locales.add(Locale.ENGLISH);
+                locales.add(Locale.US);
+                locales.add(Locale.UK);
+            }
+        } else {
+            // If the system language is not English, the fallback order will be
+            // - systemLocaleLanguageCountry  [if non-null]
+            // - systemLocaleLanguage  [if non-null]
+            // - en_US
+            // - en_GB
+            // - en
+            if (systemLocaleLanguageCountry != null) {
+                locales.add(systemLocaleLanguageCountry);
+            }
+            if (systemLocaleLanguage != null) {
+                locales.add(systemLocaleLanguage);
+            }
+            locales.add(Locale.US);
+            locales.add(Locale.UK);
+            locales.add(Locale.ENGLISH);
+        }
+        return locales;
+    }
+}
diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/textservices/TextServicesManagerService.java
similarity index 98%
rename from services/core/java/com/android/server/TextServicesManagerService.java
rename to services/core/java/com/android/server/textservices/TextServicesManagerService.java
index 40f81b3..23c29f8 100644
--- a/services/core/java/com/android/server/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/textservices/TextServicesManagerService.java
@@ -14,21 +14,21 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.textservices;
 
 import static android.view.textservice.TextServicesManager.DISABLE_PER_PROFILE_SPELL_CHECKER;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.content.PackageMonitor;
-import com.android.internal.inputmethod.InputMethodUtils;
+import com.android.internal.inputmethod.SubtypeLocaleUtils;
 import com.android.internal.textservice.ISpellCheckerService;
 import com.android.internal.textservice.ISpellCheckerServiceCallback;
 import com.android.internal.textservice.ISpellCheckerSession;
 import com.android.internal.textservice.ISpellCheckerSessionListener;
 import com.android.internal.textservice.ITextServicesManager;
 import com.android.internal.textservice.ITextServicesSessionListener;
-import com.android.internal.textservice.LazyIntToIntMap;
 import com.android.internal.util.DumpUtils;
+import com.android.server.SystemService;
 
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -461,7 +461,7 @@
         // is pre-installed or not.
         final Locale systemLocal = mContext.getResources().getConfiguration().locale;
         final ArrayList<Locale> suitableLocales =
-                InputMethodUtils.getSuitableLocalesForSpellChecker(systemLocal);
+                LocaleUtils.getSuitableLocalesForSpellChecker(systemLocal);
         if (DBG) {
             Slog.w(TAG, "findAvailSystemSpellCheckerLocked suitableLocales="
                     + Arrays.toString(suitableLocales.toArray(new Locale[suitableLocales.size()])));
@@ -475,7 +475,7 @@
                 final int subtypeCount = info.getSubtypeCount();
                 for (int subtypeIndex = 0; subtypeIndex < subtypeCount; ++subtypeIndex) {
                     final SpellCheckerSubtype subtype = info.getSubtypeAt(subtypeIndex);
-                    final Locale subtypeLocale = InputMethodUtils.constructLocaleFromString(
+                    final Locale subtypeLocale = SubtypeLocaleUtils.constructLocaleFromString(
                             subtype.getLocale());
                     if (locale.equals(subtypeLocale)) {
                         // TODO: We may have more spell checkers that fall into this category.
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 83075ed..bcf9212 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -22,17 +22,23 @@
 import android.app.IActivityManager;
 import android.app.IApplicationThread;
 import android.content.ComponentName;
+import android.content.IIntentSender;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.res.CompatibilityInfo;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.SystemClock;
 import android.service.voice.IVoiceInteractionSession;
 import android.util.SparseIntArray;
-import android.view.RemoteAnimationAdapter;
 
 import com.android.internal.app.IVoiceInteractor;
+import com.android.server.am.PendingIntentRecord;
+import com.android.server.am.SafeActivityOptions;
+import com.android.server.am.TaskRecord;
 import com.android.server.am.WindowProcessController;
 
+import java.lang.ref.WeakReference;
 import java.util.List;
 
 /**
@@ -177,6 +183,27 @@
             int userId, Intent[] intents, Bundle bOptions);
 
     /**
+     * Start intents as a package.
+     *
+     * @param uid Make a call as if this UID did.
+     * @param callingPackage Make a call as if this package did.
+     * @param intents Intents to start.
+     * @param userId Start the intents on this user.
+     * @param validateIncomingUser Set true to skip checking {@code userId} with the calling UID.
+     * @param originatingPendingIntent PendingIntentRecord that originated this activity start or
+     *        null if not originated by PendingIntent
+     */
+    public abstract int startActivitiesInPackage(int uid, String callingPackage, Intent[] intents,
+            String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId,
+            boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent);
+
+    public abstract int startActivityInPackage(int uid, int realCallingPid, int realCallingUid,
+            String callingPackage, Intent intent, String resolvedType, IBinder resultTo,
+            String resultWho, int requestCode, int startFlags, SafeActivityOptions options,
+            int userId, TaskRecord inTask, String reason, boolean validateIncomingUser,
+            PendingIntentRecord originatingPendingIntent);
+
+    /**
      * Start activity {@code intent} without calling user-id check.
      *
      * - DO NOT call it with the calling UID cleared.
@@ -267,6 +294,9 @@
     public abstract void onProcessRemoved(String name, int uid);
     public abstract void onCleanUpApplicationRecord(WindowProcessController proc);
     public abstract int getTopProcessState();
+    public abstract boolean isHeavyWeightProcess(WindowProcessController proc);
+    public abstract void clearHeavyWeightProcessIfEquals(WindowProcessController proc);
+    public abstract void finishHeavyWeightApp();
 
     public abstract boolean isSleeping();
     public abstract boolean isShuttingDown();
@@ -281,4 +311,25 @@
 
     public abstract void onPackageDataCleared(String name);
     public abstract void onPackageUninstalled(String name);
+    public abstract void onPackageAdded(String name, boolean replacing);
+
+    public abstract CompatibilityInfo compatibilityInfoForPackage(ApplicationInfo ai);
+
+    /**
+     * Set the corresponding display information for the process global configuration. To be called
+     * when we need to show IME on a different display.
+     *
+     * @param pid The process id associated with the IME window.
+     * @param displayId The ID of the display showing the IME.
+     */
+    public abstract void onImeWindowSetOnDisplay(int pid, int displayId);
+
+    public abstract void sendActivityResult(int callingUid, IBinder activityToken,
+            String resultWho, int requestCode, int resultCode, Intent data);
+    public abstract void clearPendingResultForActivity(
+            IBinder activityToken, WeakReference<PendingIntentRecord> pir);
+    public abstract IIntentSender getIntentSender(int type, String packageName,
+            int callingUid, int userId, IBinder token, String resultWho,
+            int requestCode, Intent[] intents, String[] resolvedTypes, int flags,
+            Bundle bOptions);
 }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 5d0101f..236982f 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -76,6 +76,7 @@
 import static com.android.server.wm.DisplayContentProto.ROTATION;
 import static com.android.server.wm.DisplayContentProto.SCREEN_ROTATION_ANIMATION;
 import static com.android.server.wm.DisplayContentProto.STACKS;
+import static com.android.server.wm.DisplayContentProto.SURFACE_SIZE;
 import static com.android.server.wm.DisplayContentProto.WINDOW_CONTAINER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
@@ -150,7 +151,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ToBooleanFunction;
-import com.android.internal.view.IInputMethodClient;
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.wm.utils.RotationCache;
 import com.android.server.wm.utils.WmDisplayCutout;
@@ -409,6 +409,9 @@
 
     private InputMonitor mInputMonitor;
 
+    /** Caches the value whether told display manager that we have content. */
+    private boolean mLastHasContent;
+
     /**
      * The input method window for this display.
      */
@@ -569,7 +572,7 @@
             if (!w.mLayoutAttached) {
                 if (mTmpInitial) {
                     //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
-                    w.mContentChanged = false;
+                    w.resetContentChanged();
                 }
                 if (w.mAttrs.type == TYPE_DREAM) {
                     // Don't layout windows behind a dream, so that if it does stuff like hide
@@ -614,7 +617,7 @@
                     || w.mLayoutNeeded) {
                 if (mTmpInitial) {
                     //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
-                    w.mContentChanged = false;
+                    w.resetContentChanged();
                 }
                 w.mLayoutNeeded = false;
                 w.prelayout();
@@ -697,7 +700,7 @@
         final WindowStateAnimator winAnimator = w.mWinAnimator;
 
         //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
-        w.mContentChanged = false;
+        w.resetContentChanged();
 
         // Moved from updateWindowsAndWallpaperLocked().
         if (w.mHasSurface) {
@@ -2407,6 +2410,7 @@
             screenRotationAnimation.writeToProto(proto, SCREEN_ROTATION_ANIMATION);
         }
         mDisplayFrames.writeToProto(proto, DISPLAY_FRAMES);
+        proto.write(SURFACE_SIZE, mSurfaceSize);
         proto.end(token);
     }
 
@@ -2648,6 +2652,12 @@
      */
     void setInputMethodWindowLocked(WindowState win) {
         mInputMethodWindow = win;
+        // Update display configuration for IME process.
+        if (mInputMethodWindow != null) {
+            final int imePid = mInputMethodWindow.mSession.mPid;
+            mService.mAtmInternal.onImeWindowSetOnDisplay(imePid,
+                    mInputMethodWindow.getDisplayId());
+        }
         computeImeTarget(true /* updateImeTarget */);
     }
 
@@ -2946,7 +2956,7 @@
         }
     }
 
-    boolean inputMethodClientHasFocus(IInputMethodClient client) {
+    boolean isInputMethodClientFocus(int uid, int pid) {
         final WindowState imFocus = computeImeTarget(false /* updateImeTarget */);
         if (imFocus == null) {
             return false;
@@ -2958,17 +2968,13 @@
             Slog.i(TAG_WM, "Last focus: " + mService.mLastFocus);
         }
 
-        final IInputMethodClient imeClient = imFocus.mSession.mClient;
-
         if (DEBUG_INPUT_METHOD) {
-            Slog.i(TAG_WM, "IM target client: " + imeClient);
-            if (imeClient != null) {
-                Slog.i(TAG_WM, "IM target client binder: " + imeClient.asBinder());
-                Slog.i(TAG_WM, "Requesting client binder: " + client.asBinder());
-            }
+            Slog.i(TAG_WM, "IM target uid/pid: " + imFocus.mSession.mUid
+                    + "/" + imFocus.mSession.mPid);
+            Slog.i(TAG_WM, "Requesting client uid/pid: " + uid + "/" + pid);
         }
 
-        return imeClient != null && imeClient.asBinder() == client.asBinder();
+        return imFocus.mSession.mUid == uid && imFocus.mSession.mPid == pid;
     }
 
     boolean hasSecureWindowOnScreen() {
@@ -3092,8 +3098,9 @@
         forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);
         prepareSurfaces();
 
+        mLastHasContent = mTmpApplySurfaceChangesTransactionState.displayHasContent;
         mService.mDisplayManagerInternal.setDisplayProperties(mDisplayId,
-                mTmpApplySurfaceChangesTransactionState.displayHasContent,
+                mLastHasContent,
                 mTmpApplySurfaceChangesTransactionState.preferredRefreshRate,
                 mTmpApplySurfaceChangesTransactionState.preferredModeId,
                 true /* inTraversal, must call performTraversalInTrans... below */);
@@ -3152,6 +3159,10 @@
         }
     }
 
+    int getSurfaceSize() {
+        return mSurfaceSize;
+    }
+
     void performLayout(boolean initial, boolean updateInputWindows) {
         if (!isLayoutNeeded()) {
             return;
@@ -3252,7 +3263,7 @@
         // TODO(b/68392460): We should screenshot Task controls directly
         // but it's difficult at the moment as the Task doesn't have the
         // correct size set.
-        final Bitmap bitmap = SurfaceControl.screenshot(frame, dw, dh, 0, 1, inRotation, rot);
+        final Bitmap bitmap = SurfaceControl.screenshot(frame, dw, dh, inRotation, rot);
         if (bitmap == null) {
             Slog.w(TAG_WM, "Failed to take screenshot");
             return null;
@@ -3606,6 +3617,18 @@
             final int targetPosition = findPositionForStack(position, child, false /* adding */);
             super.positionChildAt(targetPosition, child, includingParents);
 
+            if (includingParents) {
+                // We still want to move the display of this stack container to top because even the
+                // target position is adjusted to non-top, the intention of the condition is to have
+                // higher z-order to gain focus (e.g. moving a task of a fullscreen stack to front
+                // in a non-top display which is using picture-in-picture mode).
+                final int topChildPosition = getChildCount() - 1;
+                if (targetPosition < topChildPosition && position >= topChildPosition) {
+                    getParent().positionChildAt(POSITION_TOP, this /* child */,
+                            true /* includingParents */);
+                }
+            }
+
             setLayoutNeeded();
         }
 
@@ -4255,4 +4278,11 @@
     InputMonitor getInputMonitor() {
         return mInputMonitor;
     }
+
+    /**
+     * @return Cached value whether we told display manager that we have content.
+     */
+    boolean getLastHasContent() {
+        return mLastHasContent;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 685c444..bd82553 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -21,6 +21,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
+import android.app.ActivityManager;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
@@ -732,10 +733,13 @@
             boolean shouldUpdateOrientationListener = false;
 
             // Configure rotation suggestions.
-            final int showRotationSuggestions = Settings.Secure.getIntForUser(resolver,
-                    Settings.Secure.SHOW_ROTATION_SUGGESTIONS,
-                    Settings.Secure.SHOW_ROTATION_SUGGESTIONS_DEFAULT,
-                    UserHandle.USER_CURRENT);
+            final int showRotationSuggestions =
+                    ActivityManager.isLowRamDeviceStatic()
+                            ? Settings.Secure.SHOW_ROTATION_SUGGESTIONS_DISABLED
+                            : Settings.Secure.getIntForUser(resolver,
+                            Settings.Secure.SHOW_ROTATION_SUGGESTIONS,
+                            Settings.Secure.SHOW_ROTATION_SUGGESTIONS_DEFAULT,
+                            UserHandle.USER_CURRENT);
             if (mShowRotationSuggestions != showRotationSuggestions) {
                 mShowRotationSuggestions = showRotationSuggestions;
                 shouldUpdateOrientationListener = true;
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 3309798..ef3a770 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -268,11 +268,11 @@
             }
             final InputWindowHandle dragWindowHandle =
                     mService.mDragDropController.getInputWindowHandleLocked();
-            if (dragWindowHandle != null) {
-                addInputWindowHandle(dragWindowHandle);
-            } else {
+            if (dragWindowHandle == null) {
                 Slog.w(TAG_WM, "Drag is in progress but there is no "
                         + "drag window handle.");
+            } else if (dragWindowHandle.displayId == mDisplayId) {
+                addInputWindowHandle(dragWindowHandle);
             }
         }
 
@@ -283,11 +283,11 @@
             }
             final InputWindowHandle dragWindowHandle =
                     mService.mTaskPositioningController.getDragWindowHandleLocked();
-            if (dragWindowHandle != null) {
-                addInputWindowHandle(dragWindowHandle);
-            } else {
+            if (dragWindowHandle == null) {
                 Slog.e(TAG_WM,
                         "Repositioning is in progress but there is no drag window handle.");
+            } else if (dragWindowHandle.displayId == mDisplayId) {
+                addInputWindowHandle(dragWindowHandle);
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 1eae567..e718c7b 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -20,8 +20,8 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.view.RemoteAnimationTarget.MODE_CLOSING;
+import static android.view.RemoteAnimationTarget.MODE_OPENING;
 import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
-
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM;
 import static com.android.server.wm.AnimationAdapterProto.REMOTE;
@@ -48,16 +48,13 @@
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
-
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.LocalServices;
 import com.android.server.input.InputWindowHandle;
 import com.android.server.inputmethod.InputMethodManagerInternal;
 import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
 import com.android.server.wm.utils.InsetUtils;
-
 import com.google.android.collect.Sets;
-
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
@@ -93,6 +90,7 @@
 
     // The recents component app token that is shown behind the visibile tasks
     private AppWindowToken mTargetAppToken;
+    private int mTargetActivityType;
     private Rect mMinimizedHomeBounds = new Rect();
 
     // We start the RecentsAnimationController in a pending-start state since we need to wait for
@@ -259,23 +257,37 @@
         mDisplayId = displayId;
     }
 
+    public void initialize(int targetActivityType, SparseBooleanArray recentTaskIds) {
+        initialize(mService.mRoot.getDisplayContent(mDisplayId), targetActivityType, recentTaskIds);
+    }
+
     /**
      * Initializes the recents animation controller. This is a separate call from the constructor
      * because it may call cancelAnimation() which needs to properly clean up the controller
      * in the window manager.
      */
-    public void initialize(int targetActivityType, SparseBooleanArray recentTaskIds) {
-        // Make leashes for each of the visible tasks and add it to the recents animation to be
-        // started
-        final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
+    @VisibleForTesting
+    void initialize(DisplayContent dc, int targetActivityType, SparseBooleanArray recentTaskIds) {
+        mTargetActivityType = targetActivityType;
+
+        // Make leashes for each of the visible/target tasks and add it to the recents animation to
+        // be started
         final ArrayList<Task> visibleTasks = dc.getVisibleTasks();
+        final TaskStack targetStack = dc.getStack(WINDOWING_MODE_UNDEFINED, targetActivityType);
+        if (targetStack != null) {
+            for (int i = targetStack.getChildCount() - 1; i >= 0; i--) {
+                final Task t = targetStack.getChildAt(i);
+                if (!visibleTasks.contains(t)) {
+                    visibleTasks.add(t);
+                }
+            }
+        }
         final int taskCount = visibleTasks.size();
         for (int i = 0; i < taskCount; i++) {
             final Task task = visibleTasks.get(i);
             final WindowConfiguration config = task.getWindowConfiguration();
             if (config.tasksAreFloating()
-                    || config.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
-                    || config.getActivityType() == targetActivityType) {
+                    || config.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
                 continue;
             }
             addAnimation(task, !recentTaskIds.get(task.mTaskId));
@@ -586,7 +598,10 @@
             final Rect insets = new Rect();
             mainWindow.getContentInsets(insets);
             InsetUtils.addInsets(insets, mainWindow.mAppToken.getLetterboxInsets());
-            mTarget = new RemoteAnimationTarget(mTask.mTaskId, MODE_CLOSING, mCapturedLeash,
+            final int mode = topApp.getActivityType() == mTargetActivityType
+                    ? MODE_OPENING
+                    : MODE_CLOSING;
+            mTarget = new RemoteAnimationTarget(mTask.mTaskId, mode, mCapturedLeash,
                     !topApp.fillsParent(), mainWindow.mWinAnimator.mLastClipRect,
                     insets, mTask.getPrefixOrderIndex(), mPosition, mBounds,
                     mTask.getWindowConfiguration(), mIsRecentTaskInvisible);
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index d92818a..a9571be 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -48,7 +48,6 @@
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
 import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_NONE;
 import static com.android.server.wm.WindowManagerService.logSurface;
-import static com.android.server.wm.WindowSurfacePlacer.SET_FORCE_HIDING_CHANGED;
 import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
 import static com.android.server.wm.WindowSurfacePlacer.SET_UPDATE_ROTATION;
 import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_ACTION_PENDING;
@@ -91,7 +90,6 @@
     private static final int SET_SCREEN_BRIGHTNESS_OVERRIDE = 1;
     private static final int SET_USER_ACTIVITY_TIMEOUT = 2;
 
-    private boolean mWallpaperForceHidingChanged = false;
     private Object mLastWindowFreezeSource = null;
     private Session mHoldScreen = null;
     private float mScreenBrightness = -1;
@@ -626,18 +624,6 @@
             recentsAnimationController.checkAnimationReady(mWallpaperController);
         }
 
-        if (mWallpaperForceHidingChanged && defaultDisplay.pendingLayoutChanges == 0
-                && !mService.mAppTransition.isReady()) {
-            // At this point, there was a window with a wallpaper that was force hiding other
-            // windows behind it, but now it is going away. This may be simple -- just animate away
-            // the wallpaper and its window -- or it may be hard -- the wallpaper now needs to be
-            // shown behind something that was hidden.
-            defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_LAYOUT;
-            if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats(
-                    "after animateAwayWallpaperLocked", defaultDisplay.pendingLayoutChanges);
-        }
-        mWallpaperForceHidingChanged = false;
-
         if (mWallpaperMayChange) {
             if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Wallpaper may change!  Adjusting");
             defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
@@ -961,10 +947,6 @@
             mWallpaperMayChange = true;
             doRequest = true;
         }
-        if ((bulkUpdateParams & SET_FORCE_HIDING_CHANGED) != 0) {
-            mWallpaperForceHidingChanged = true;
-            doRequest = true;
-        }
         if ((bulkUpdateParams & SET_ORIENTATION_CHANGE_COMPLETE) == 0) {
             mOrientationChangeComplete = false;
         } else {
diff --git a/services/core/java/com/android/server/wm/SeamlessRotator.java b/services/core/java/com/android/server/wm/SeamlessRotator.java
index 6f597277..95ca0a6 100644
--- a/services/core/java/com/android/server/wm/SeamlessRotator.java
+++ b/services/core/java/com/android/server/wm/SeamlessRotator.java
@@ -16,12 +16,12 @@
 
 package com.android.server.wm;
 
-import static android.view.Surface.ROTATION_180;
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
 
 import android.graphics.Matrix;
 import android.view.DisplayInfo;
+import android.view.Surface;
 import android.view.Surface.Rotation;
 import android.view.SurfaceControl.Transaction;
 
@@ -33,10 +33,10 @@
 /**
  * Helper class for seamless rotation.
  *
- * Works by transforming the window token back into the old display rotation.
+ * Works by transforming the {@link WindowState} back into the old display rotation.
  *
- * Uses deferTransactionUntil instead of latching on the buffer size to allow for seamless 180
- * degree rotations.
+ * Uses {@link android.view.SurfaceControl#deferTransactionUntil(Surface, long)} instead of
+ * latching on the buffer size to allow for seamless 180 degree rotations.
  */
 public class SeamlessRotator {
 
@@ -45,7 +45,7 @@
     private final int mOldRotation;
     private final int mNewRotation;
 
-    public SeamlessRotator(int oldRotation, int newRotation, DisplayInfo info) {
+    public SeamlessRotator(@Rotation int oldRotation, @Rotation int newRotation, DisplayInfo info) {
         mOldRotation = oldRotation;
         mNewRotation = newRotation;
 
@@ -60,11 +60,16 @@
     }
 
     /**
-     * Applies a transform to the window token's surface that undoes the effect of the global
+     * Applies a transform to the {@link WindowState} surface that undoes the effect of the global
      * display rotation.
      */
-    public void unrotate(Transaction transaction, WindowToken token) {
-        transaction.setMatrix(token.getSurfaceControl(), mTransform, mFloat9);
+    public void unrotate(Transaction transaction, WindowState win) {
+        transaction.setMatrix(win.getSurfaceControl(), mTransform, mFloat9);
+
+        // WindowState sets the position of the window so transform the position and update it.
+        final float[] winSurfacePos = {win.mLastSurfacePosition.x, win.mLastSurfacePosition.y};
+        mTransform.mapPoints(winSurfacePos);
+        transaction.setPosition(win.getSurfaceControl(), winSurfacePos[0], winSurfacePos[1]);
     }
 
     /**
@@ -78,27 +83,23 @@
     }
 
     /**
-     * Removes the transform to the window token's surface that undoes the effect of the global
-     * display rotation.
+     * Removes the transform and sets the previously known surface position for {@link WindowState}
+     * surface that undoes the effect of the global display rotation.
      *
-     * Removing the transform and the result of the WindowState's layout are both tied to the
-     * WindowState's next frame, such that they apply at the same time the client draws the
+     * Removing the transform and the result of the {@link WindowState} layout are both tied to the
+     * {@link WindowState} next frame, such that they apply at the same time the client draws the
      * window in the new orientation.
      */
-    public void finish(WindowToken token, WindowState win) {
+    public void finish(WindowState win) {
         mTransform.reset();
-        token.getPendingTransaction().setMatrix(token.mSurfaceControl, mTransform, mFloat9);
+        final Transaction t = win.getPendingTransaction();
+        t.setMatrix(win.mSurfaceControl, mTransform, mFloat9);
+        t.setPosition(win.mSurfaceControl, win.mLastSurfacePosition.x, win.mLastSurfacePosition.y);
         if (win.mWinAnimator.mSurfaceController != null) {
-            token.getPendingTransaction().deferTransactionUntil(token.mSurfaceControl,
-                    win.mWinAnimator.mSurfaceController.mSurfaceControl.getHandle(),
-                    win.getFrameNumber());
-            win.getPendingTransaction().deferTransactionUntil(win.mSurfaceControl,
-                    win.mWinAnimator.mSurfaceController.mSurfaceControl.getHandle(),
-                    win.getFrameNumber());
-            win.getPendingTransaction().deferTransactionUntil(
-                    win.mWinAnimator.mSurfaceController.mSurfaceControl,
-                    win.mWinAnimator.mSurfaceController.mSurfaceControl.getHandle(),
-                    win.getFrameNumber());
+            t.deferTransactionUntil(win.mSurfaceControl,
+                    win.mWinAnimator.mSurfaceController.getHandle(), win.getFrameNumber());
+            t.deferTransactionUntil(win.mWinAnimator.mSurfaceController.mSurfaceControl,
+                    win.mWinAnimator.mSurfaceController.getHandle(), win.getFrameNumber());
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index f9a71d3..acc9c03 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -38,7 +38,6 @@
 import android.os.Parcel;
 import android.os.Process;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.Trace;
 import android.os.UserHandle;
 import android.util.MergedConfiguration;
@@ -56,10 +55,6 @@
 import android.view.WindowManager;
 
 import com.android.internal.os.logging.MetricsLoggerWrapper;
-import com.android.internal.view.IInputContext;
-import com.android.internal.view.IInputMethodClient;
-import com.android.server.LocalServices;
-import com.android.server.inputmethod.InputMethodManagerInternal;
 import com.android.server.wm.WindowManagerService.H;
 
 import java.io.PrintWriter;
@@ -73,8 +68,6 @@
 class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
     final WindowManagerService mService;
     final IWindowSessionCallback mCallback;
-    final IInputMethodClient mClient;
-    final InputMethodManagerInternal mInputMethodManagerInternal;
     final int mUid;
     final int mPid;
     private final String mStringName;
@@ -95,17 +88,9 @@
     private String mPackageName;
     private String mRelayoutTag;
 
-    public Session(WindowManagerService service, IWindowSessionCallback callback,
-            IInputMethodClient client, IInputContext inputContext) {
+    public Session(WindowManagerService service, IWindowSessionCallback callback) {
         mService = service;
         mCallback = callback;
-        mClient = client;
-        // Depending on the timing when Session object gets called and SystemServer#mFactoryTestMode
-        // this could be null, right?
-        final InputMethodManagerInternal immInternal =
-                LocalServices.getService(InputMethodManagerInternal.class);
-        mInputMethodManagerInternal =
-                immInternal != null ? immInternal : InputMethodManagerInternal.NOP;
         mUid = Binder.getCallingUid();
         mPid = Binder.getCallingPid();
         mLastReportedAnimatorScale = service.getCurrentAnimatorScale();
@@ -134,12 +119,11 @@
         sb.append("}");
         mStringName = sb.toString();
 
-        mInputMethodManagerInternal.addClient(client, inputContext, mUid, mPid);
         try {
-            client.asBinder().linkToDeath(this, 0);
+            mCallback.asBinder().linkToDeath(this, 0);
         } catch (RemoteException e) {
             // The caller has died, so we can just forget about this.
-            mInputMethodManagerInternal.removeClient(client);
+            // Hmmm, should we call killSessionLocked()??
         }
     }
 
@@ -159,9 +143,8 @@
 
     @Override
     public void binderDied() {
-        mInputMethodManagerInternal.removeClient(mClient);
         synchronized(mService.mWindowMap) {
-            mClient.asBinder().unlinkToDeath(this, 0);
+            mCallback.asBinder().unlinkToDeath(this, 0);
             mClientDead = true;
             killSessionLocked();
         }
diff --git a/services/core/java/com/android/server/wm/TEST_MAPPING b/services/core/java/com/android/server/wm/TEST_MAPPING
index c99329a..0c9a14b 100644
--- a/services/core/java/com/android/server/wm/TEST_MAPPING
+++ b/services/core/java/com/android/server/wm/TEST_MAPPING
@@ -21,7 +21,7 @@
           "include-annotation": "android.platform.test.annotations.Presubmit"
         },
         {
-          "exclude-annotation": "android.support.test.filters.FlakyTest"
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
         }
       ]
     },
@@ -35,7 +35,7 @@
           "include-annotation": "android.platform.test.annotations.Presubmit"
         },
         {
-          "exclude-annotation": "android.support.test.filters.FlakyTest"
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
         }
       ]
     }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index eb419c9..6aa0e01 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -29,6 +29,8 @@
 import static com.android.server.wm.TaskProto.DEFER_REMOVAL;
 import static com.android.server.wm.TaskProto.FILLS_PARENT;
 import static com.android.server.wm.TaskProto.ID;
+import static com.android.server.wm.TaskProto.SURFACE_HEIGHT;
+import static com.android.server.wm.TaskProto.SURFACE_WIDTH;
 import static com.android.server.wm.TaskProto.TEMP_INSET_BOUNDS;
 import static com.android.server.wm.TaskProto.WINDOW_CONTAINER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
@@ -297,6 +299,12 @@
         return boundsChange;
     }
 
+    @Override
+    void onDisplayChanged(DisplayContent dc) {
+        updateSurfaceSize(dc);
+        super.onDisplayChanged(dc);
+    }
+
     /**
      * Sets the bounds used to calculate the insets. See
      * {@link android.app.IActivityTaskManager#resizeDockedStack} why this is needed.
@@ -553,9 +561,10 @@
 
     @Override
     public SurfaceControl getAnimationLeashParent() {
-        // Reparent to the animation layer so that we aren't clipped by the non-minimized
-        // stack bounds, currently we only animate the task for the recents animation
-        return getAppAnimationLayer(ANIMATION_LAYER_STANDARD);
+        // Currently, only the recents animation will create animation leashes for tasks. In this
+        // case, reparent the task to the home animation layer while it is being animated to allow
+        // the home activity to reorder the app windows relative to its own.
+        return getAppAnimationLayer(ANIMATION_LAYER_HOME);
     }
 
     boolean isTaskAnimating() {
@@ -703,6 +712,8 @@
         getBounds().writeToProto(proto, BOUNDS);
         mTempInsetBounds.writeToProto(proto, TEMP_INSET_BOUNDS);
         proto.write(DEFER_REMOVAL, mDeferRemoval);
+        proto.write(SURFACE_WIDTH, mSurfaceControl.getWidth());
+        proto.write(SURFACE_HEIGHT, mSurfaceControl.getHeight());
         proto.end(token);
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 8effc6b..d2696c0 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -19,17 +19,17 @@
 import static android.app.ActivityTaskManager.RESIZE_MODE_USER;
 import static android.app.ActivityTaskManager.RESIZE_MODE_USER_FORCED;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+
+import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
 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.dipToPixel;
-import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
 import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP;
 import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP;
 
 import android.annotation.IntDef;
-import android.app.IActivityManager;
 import android.app.IActivityTaskManager;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -51,7 +51,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.input.InputApplicationHandle;
 import com.android.server.input.InputWindowHandle;
-import com.android.server.wm.WindowManagerService.H;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -209,7 +208,6 @@
                     // Post back to WM to handle clean-ups. We still need the input
                     // event handler for the last finishInputEvent()!
                     mService.mTaskPositioningController.finishTaskPositioning();
-                    mTask.getDisplayContent().getInputMonitor().updateInputWindowsLw(true /*force*/);
                 }
                 handled = true;
             } catch (Exception e) {
@@ -237,7 +235,7 @@
     }
 
     /**
-     * @param display The Display that the window being dragged is on.
+     * @param displayContent The Display that the window being dragged is on.
      */
     void register(DisplayContent displayContent) {
         final Display display = displayContent.getDisplay();
@@ -303,6 +301,9 @@
         }
         mDisplayContent.pauseRotationLocked();
 
+        // Notify InputMonitor to take mDragWindowHandle.
+        mDisplayContent.getInputMonitor().updateInputWindowsLw(true /*force*/);
+
         mSideMargin = dipToPixel(SIDE_MARGIN_DIP, mDisplayMetrics);
         mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, mDisplayMetrics);
         mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, mDisplayMetrics);
@@ -334,6 +335,9 @@
         mDragApplicationHandle = null;
         mDragEnded = true;
 
+        // Notify InputMonitor to remove mDragWindowHandle.
+        mDisplayContent.getInputMonitor().updateInputWindowsLw(true /*force*/);
+
         // Resume rotations after a drag.
         if (DEBUG_ORIENTATION) {
             Slog.d(TAG, "Resuming rotation after re-position");
diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java
index 9cdc6b7..33416f6 100644
--- a/services/core/java/com/android/server/wm/TaskPositioningController.java
+++ b/services/core/java/com/android/server/wm/TaskPositioningController.java
@@ -20,14 +20,13 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.annotation.Nullable;
-import android.app.IActivityManager;
 import android.app.IActivityTaskManager;
-import android.os.RemoteException;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.RemoteException;
 import android.util.Slog;
-import android.view.Display;
 import android.view.IWindow;
+
 import com.android.internal.annotations.GuardedBy;
 import com.android.server.input.InputManagerService;
 import com.android.server.input.InputWindowHandle;
@@ -124,10 +123,8 @@
             return false;
         }
 
-        Display display = displayContent.getDisplay();
         mTaskPositioner = TaskPositioner.create(mService);
         mTaskPositioner.register(displayContent);
-        displayContent.getInputMonitor().updateInputWindowsLw(true /*force*/);
 
         // We need to grab the touch focus so that the touch events during the
         // resizing/scrolling are not sent to the app. 'win' is the main window
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 793ffce..a1d6ffd 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -284,9 +284,6 @@
         if ((bulkUpdateParams & WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE) != 0) {
             builder.append(" WALLPAPER_MAY_CHANGE");
         }
-        if ((bulkUpdateParams & WindowSurfacePlacer.SET_FORCE_HIDING_CHANGED) != 0) {
-            builder.append(" FORCE_HIDING_CHANGED");
-        }
         if ((bulkUpdateParams & WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE) != 0) {
             builder.append(" ORIENTATION_CHANGE_COMPLETE");
         }
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 8e704a8..4883f97 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -20,13 +20,14 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.view.SurfaceControl.Transaction;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
-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.WindowContainerProto.CONFIGURATION_CONTAINER;
 import static com.android.server.wm.WindowContainerProto.ORIENTATION;
 import static com.android.server.wm.WindowContainerProto.SURFACE_ANIMATOR;
 import static com.android.server.wm.WindowContainerProto.VISIBLE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.annotation.CallSuper;
 import android.annotation.IntDef;
@@ -41,10 +42,8 @@
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Builder;
 import android.view.SurfaceSession;
-
 import com.android.internal.util.ToBooleanFunction;
 import com.android.server.wm.SurfaceAnimator.Animatable;
-
 import java.io.PrintWriter;
 import java.util.Comparator;
 import java.util.LinkedList;
@@ -70,7 +69,8 @@
 
     /**
      * Animation layer that is reserved for {@link WindowConfiguration#ACTIVITY_TYPE_HOME}
-     * activities that happens below all {@link TaskStack}s.
+     * activities and all activities that are being controlled by the recents animation. This
+     * layer is generally below all {@link TaskStack}s.
      */
     static final int ANIMATION_LAYER_HOME = 2;
 
@@ -503,6 +503,24 @@
         }
     }
 
+    /**
+     * Update the surface size when display changed in order to avoid children being bound by the
+     * old display size.
+     *
+     * Note that we don't want to apply this to all layers, but only limiting this to layers that
+     * don't set their own size ({@link Task}, {@link WindowState} and {@link WindowToken}).
+     */
+    void updateSurfaceSize(DisplayContent dc) {
+        if (mSurfaceControl == null) {
+            return;
+        }
+
+        final int newSurfaceSize = dc.getSurfaceSize();
+        if (mSurfaceControl.getWidth() != newSurfaceSize) {
+            getPendingTransaction().setSize(mSurfaceControl, newSurfaceSize, newSurfaceSize);
+        }
+    }
+
     void setWaitingForDrawnIfResizingChanged() {
         for (int i = mChildren.size() - 1; i >= 0; --i) {
             final WindowContainer wc = mChildren.get(i);
diff --git a/services/core/java/com/android/server/wm/WindowFrames.java b/services/core/java/com/android/server/wm/WindowFrames.java
index 9381fc6..20a874b 100644
--- a/services/core/java/com/android/server/wm/WindowFrames.java
+++ b/services/core/java/com/android/server/wm/WindowFrames.java
@@ -36,7 +36,6 @@
 import android.graphics.Rect;
 import android.util.proto.ProtoOutputStream;
 import android.view.DisplayCutout;
-import android.view.WindowManager;
 
 import com.android.server.wm.utils.InsetUtils;
 import com.android.server.wm.utils.WmDisplayCutout;
@@ -191,6 +190,10 @@
 
     private final Rect mTmpRect = new Rect();
 
+    private boolean mHasOutsets;
+
+    private boolean mContentChanged;
+
     public WindowFrames() {
     }
 
@@ -237,11 +240,9 @@
      * Calculates the outsets for this windowFrame. The outsets are calculated by the area between
      * the {@link #mOutsetFrame} and the {@link #mContentFrame}. If there are no outsets, then
      * {@link #mOutsets} is set to empty.
-     *
-     * @param hasOutsets Whether this frame has outsets.
      */
-    void calculateOutsets(boolean hasOutsets) {
-        if (hasOutsets) {
+    void calculateOutsets() {
+        if (mHasOutsets) {
             InsetUtils.insetsBetweenFrames(mOutsetFrame, mContentFrame, mOutsets);
         } else {
             mOutsets.setEmpty();
@@ -249,7 +250,8 @@
     }
 
     /**
-     * Calculate the insets for the type {@link WindowManager.LayoutParams#TYPE_DOCK_DIVIDER}
+     * Calculate the insets for the type
+     * {@link android.view.WindowManager.LayoutParams#TYPE_DOCK_DIVIDER}
      *
      * @param cutoutInsets The insets for the cutout.
      */
@@ -286,8 +288,9 @@
         boolean overrideBottomInset = !windowsAreFloating && !inFullscreenContainer
                 && mFrame.bottom > windowBounds.bottom;
 
-        mTmpRect.set(mFrame.left, mFrame.top, overrideRightInset ? mTmpRect.right : mFrame.right,
-                overrideBottomInset ? mTmpRect.bottom : mFrame.bottom);
+        mTmpRect.set(mFrame.left, mFrame.top,
+                overrideRightInset ? windowBounds.right : mFrame.right,
+                overrideBottomInset ? windowBounds.bottom : mFrame.bottom);
 
         InsetUtils.insetsBetweenFrames(mTmpRect, mContentFrame, mContentInsets);
         InsetUtils.insetsBetweenFrames(mTmpRect, mVisibleFrame, mVisibleInsets);
@@ -366,6 +369,28 @@
         mLastContentInsets.set(-1, -1, -1, -1);
     }
 
+    /**
+     * Sets whether the frame has outsets.
+     */
+    public void setHasOutsets(boolean hasOutsets) {
+        mHasOutsets = hasOutsets;
+    }
+
+    /**
+     * Sets whether the content has changed. This means that either the size or parent frame has
+     * changed.
+     */
+    public void setContentChanged(boolean contentChanged) {
+        mContentChanged = contentChanged;
+    }
+
+    /**
+     * @see #setContentChanged(boolean)
+     */
+    boolean hasContentChanged() {
+        return mContentChanged;
+    }
+
     public void writeToProto(@NonNull ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         mParentFrame.writeToProto(proto, PARENT_FRAME);
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 793ce60..5410676 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ClipData;
+import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.hardware.display.DisplayManagerInternal;
@@ -30,7 +31,6 @@
 import android.view.MagnificationSpec;
 import android.view.WindowInfo;
 
-import com.android.internal.view.IInputMethodClient;
 import com.android.server.input.InputManagerService;
 import com.android.server.policy.WindowManagerPolicy;
 
@@ -340,20 +340,6 @@
     public abstract int getInputMethodWindowVisibleHeight(int displayId);
 
     /**
-      * Saves last input method window for transition.
-      *
-      * Note that it is assumed that this method is called only by InputMethodManagerService.
-      */
-    public abstract void saveLastInputMethodWindowForTransition();
-
-    /**
-     * Clears last input method window for transition.
-     *
-     * Note that it is assumed that this method is called only by InputMethodManagerService.
-     */
-    public abstract void clearLastInputMethodWindowForTransition();
-
-    /**
      * Notifies WindowManagerService that the current IME window status is being changed.
      *
      * <p>Only {@link com.android.server.inputmethod.InputMethodManagerService} is the expected and
@@ -444,12 +430,24 @@
     public abstract boolean isUidFocused(int uid);
 
     /**
-     * Returns {@code true} if a process that is identified by {@code client} has IME focus.
+     * Checks whether the specified process has IME focus or not.
+     *
+     * @param uid UID of the process to be queried
+     * @param pid PID of the process to be queried
+     * @return {@code true} if a process that is identified by {@code uid} and {@code pid} has IME
+     *         focus
      */
-    public abstract boolean inputMethodClientHasFocus(IInputMethodClient client);
+    public abstract boolean isInputMethodClientFocus(int uid, int pid);
 
     /**
      * Return the display Id for given window.
      */
     public abstract int getDisplayIdForWindow(IBinder windowToken);
+
+    // TODO: use WindowProcessController once go/wm-unified is done.
+    /**
+     * Notifies the window manager that configuration of the process associated with the input pid
+     * changed.
+     */
+    public abstract void onProcessConfigurationChanged(int pid, Configuration newConfig);
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2ed09ae..b627df4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -182,6 +182,7 @@
 import android.util.MergedConfiguration;
 import android.util.Pair;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 import android.util.TimeUtils;
@@ -226,14 +227,13 @@
 import android.view.WindowManagerPolicyConstants.PointerEventListener;
 
 import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IShortcutService;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.LatencyTracker;
-import com.android.internal.view.IInputContext;
-import com.android.internal.view.IInputMethodClient;
 import com.android.internal.view.WindowManagerPolicyThread;
 import com.android.server.AnimationThread;
 import com.android.server.DisplayThread;
@@ -482,6 +482,10 @@
      */
     WindowState[] mPendingRemoveTmp = new WindowState[20];
 
+    // TODO: use WindowProcessController once go/wm-unified is done.
+    /** Mapping of process pids to configurations */
+    final SparseArray<Configuration> mProcessConfigurations = new SparseArray<>();
+
     /**
      * Windows whose surface should be destroyed.
      */
@@ -1411,7 +1415,6 @@
 
             win.mToken.addWindow(win);
             if (type == TYPE_INPUT_METHOD) {
-                win.mGivenInsetsPending = true;
                 displayContent.setInputMethodWindowLocked(win);
                 imMayMove = false;
             } else if (type == TYPE_INPUT_METHOD_DIALOG) {
@@ -2712,6 +2715,11 @@
         }
     }
 
+    @VisibleForTesting
+    void setRecentsAnimationController(RecentsAnimationController controller) {
+        mRecentsAnimationController = controller;
+    }
+
     public RecentsAnimationController getRecentsAnimationController() {
         return mRecentsAnimationController;
     }
@@ -5037,12 +5045,8 @@
     // -------------------------------------------------------------
 
     @Override
-    public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,
-            IInputContext inputContext) {
-        if (client == null) throw new IllegalArgumentException("null client");
-        if (inputContext == null) throw new IllegalArgumentException("null inputContext");
-        Session session = new Session(this, callback, client, inputContext);
-        return session;
+    public IWindowSession openSession(IWindowSessionCallback callback) {
+        return new Session(this, callback);
     }
 
     @Override
@@ -5075,9 +5079,7 @@
             throw new SecurityException("Must hold permission " +
                     android.Manifest.permission.WRITE_SECURE_SETTINGS);
         }
-        if (displayId != DEFAULT_DISPLAY) {
-            throw new IllegalArgumentException("Can only set the default display");
-        }
+
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized(mWindowMap) {
@@ -5110,9 +5112,7 @@
             throw new SecurityException("Must hold permission " +
                     android.Manifest.permission.WRITE_SECURE_SETTINGS);
         }
-        if (displayId != DEFAULT_DISPLAY) {
-            throw new IllegalArgumentException("Can only set the default display");
-        }
+
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized(mWindowMap) {
@@ -5192,9 +5192,7 @@
             throw new SecurityException("Must hold permission " +
                     android.Manifest.permission.WRITE_SECURE_SETTINGS);
         }
-        if (displayId != DEFAULT_DISPLAY) {
-            throw new IllegalArgumentException("Can only set the default display");
-        }
+
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized(mWindowMap) {
@@ -5241,9 +5239,6 @@
             throw new SecurityException("Must hold permission " +
                     android.Manifest.permission.WRITE_SECURE_SETTINGS);
         }
-        if (displayId != DEFAULT_DISPLAY) {
-            throw new IllegalArgumentException("Can only set the default display");
-        }
 
         final int targetUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
                 Binder.getCallingUid(), userId, false, true, "setForcedDisplayDensityForUser",
@@ -5272,9 +5267,6 @@
             throw new SecurityException("Must hold permission " +
                     android.Manifest.permission.WRITE_SECURE_SETTINGS);
         }
-        if (displayId != DEFAULT_DISPLAY) {
-            throw new IllegalArgumentException("Can only set the default display");
-        }
 
         final int callingUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
                 Binder.getCallingUid(), userId, false, true, "clearForcedDisplayDensityForUser",
@@ -5683,11 +5675,6 @@
 
         mInputManagerCallback.freezeInputDispatchingLw();
 
-        // Clear the last input window -- that is just used for
-        // clean transitions between IMEs, and if we are freezing
-        // the screen then the whole world is changing behind the scenes.
-        mPolicy.setLastInputMethodWindowLw(null, null);
-
         if (mAppTransition.isTransitionSet()) {
             mAppTransition.freeze();
         }
@@ -7300,23 +7287,6 @@
         }
 
         @Override
-        public void saveLastInputMethodWindowForTransition() {
-            synchronized (mWindowMap) {
-                final WindowState imeWindow = mRoot.getCurrentInputMethodWindow();
-                if (imeWindow != null) {
-                    mPolicy.setLastInputMethodWindowLw(imeWindow, mInputMethodTarget);
-                }
-            }
-        }
-
-        @Override
-        public void clearLastInputMethodWindowForTransition() {
-            synchronized (mWindowMap) {
-                mPolicy.setLastInputMethodWindowLw(null, null);
-            }
-        }
-
-        @Override
         public void updateInputMethodWindowStatus(@NonNull IBinder imeToken,
                 boolean imeWindowVisible, boolean dismissImeOnBackKeyPressed) {
             mPolicy.setDismissImeOnBackKeyPressed(dismissImeOnBackKeyPressed);
@@ -7411,32 +7381,32 @@
             }
         }
 
-    public boolean inputMethodClientHasFocus(IInputMethodClient client) {
-        boolean hasFocus;
-        synchronized (mWindowMap) {
-            // Check all displays if any input method window has focus.
-            for (int i = mRoot.mChildren.size() - 1; i >= 0; --i) {
-                final DisplayContent displayContent = mRoot.mChildren.get(i);
-                if (displayContent.inputMethodClientHasFocus(client)) {
+        @Override
+        public boolean isInputMethodClientFocus(int uid, int pid) {
+            synchronized (mWindowMap) {
+                // Check all displays if any input method window has focus.
+                for (int i = mRoot.mChildren.size() - 1; i >= 0; --i) {
+                    final DisplayContent displayContent = mRoot.mChildren.get(i);
+                    if (displayContent.isInputMethodClientFocus(uid, pid)) {
+                        return true;
+                    }
+                }
+
+                // Okay, how about this...  what is the current focus?
+                // It seems in some cases we may not have moved the IM
+                // target window, such as when it was in a pop-up window,
+                // so let's also look at the current focus.  (An example:
+                // go to Gmail, start searching so the keyboard goes up,
+                // press home.  Sometimes the IME won't go down.)
+                // Would be nice to fix this more correctly, but it's
+                // way at the end of a release, and this should be good enough.
+                if (mCurrentFocus != null && mCurrentFocus.mSession.mUid == uid
+                        && mCurrentFocus.mSession.mPid == pid) {
                     return true;
                 }
             }
-
-            // Okay, how about this...  what is the current focus?
-            // It seems in some cases we may not have moved the IM
-            // target window, such as when it was in a pop-up window,
-            // so let's also look at the current focus.  (An example:
-            // go to Gmail, start searching so the keyboard goes up,
-            // press home.  Sometimes the IME won't go down.)
-            // Would be nice to fix this more correctly, but it's
-            // way at the end of a release, and this should be good enough.
-            if (mCurrentFocus != null && mCurrentFocus.mSession.mClient != null
-                    && mCurrentFocus.mSession.mClient.asBinder() == client.asBinder()) {
-                return true;
-            }
+            return false;
         }
-        return false;
-    }
 
         @Override
         public int getDisplayIdForWindow(IBinder windowToken) {
@@ -7448,6 +7418,19 @@
                 return Display.INVALID_DISPLAY;
             }
         }
+
+        @Override
+        public void onProcessConfigurationChanged(int pid, Configuration newConfig) {
+            synchronized (mWindowMap) {
+                Configuration currentConfig = mProcessConfigurations.get(pid);
+                if (currentConfig == null) {
+                    currentConfig = new Configuration(newConfig);
+                } else {
+                    currentConfig.setTo(newConfig);
+                }
+                mProcessConfigurations.put(pid, currentConfig);
+            }
+        }
     }
 
     void registerAppFreezeListener(AppFreezeListener listener) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index 6e0ccfd..831418b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -20,7 +20,6 @@
 
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.ShellCommand;
 import android.os.UserHandle;
@@ -28,10 +27,6 @@
 import android.view.Display;
 import android.view.IWindowManager;
 
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.io.PrintWriter;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -87,21 +82,48 @@
         return -1;
     }
 
+    private int getDisplayId(String opt) {
+        int displayId = Display.DEFAULT_DISPLAY;
+        String option = "-d".equals(opt) ? opt : getNextOption();
+        if (option != null && "-d".equals(option)) {
+            try {
+                displayId = Integer.parseInt(getNextArgRequired());
+            } catch (NumberFormatException e) {
+                getErrPrintWriter().println("Error: bad number " + e);
+            } catch (IllegalArgumentException e) {
+                getErrPrintWriter().println("Error: " + e);
+            }
+        }
+        return displayId;
+    }
+
+    private void printInitialDisplaySize(PrintWriter pw , int displayId) {
+        final Point initialSize = new Point();
+        final Point baseSize = new Point();
+
+        try {
+            mInterface.getInitialDisplaySize(displayId, initialSize);
+            mInterface.getBaseDisplaySize(displayId, baseSize);
+            pw.println("Physical size: " + initialSize.x + "x" + initialSize.y);
+            if (!initialSize.equals(baseSize)) {
+                pw.println("Override size: " + baseSize.x + "x" + baseSize.y);
+            }
+        } catch (RemoteException e) {
+            // Can't call getInitialDisplaySize() on IWindowManager or
+            // Can't call getBaseDisplaySize() on IWindowManager
+            pw.println("Remote exception: " + e);
+        }
+    }
+
     private int runDisplaySize(PrintWriter pw) throws RemoteException {
         String size = getNextArg();
         int w, h;
+        final int displayId = getDisplayId(size);
         if (size == null) {
-            Point initialSize = new Point();
-            Point baseSize = new Point();
-            try {
-                mInterface.getInitialDisplaySize(Display.DEFAULT_DISPLAY, initialSize);
-                mInterface.getBaseDisplaySize(Display.DEFAULT_DISPLAY, baseSize);
-                pw.println("Physical size: " + initialSize.x + "x" + initialSize.y);
-                if (!initialSize.equals(baseSize)) {
-                    pw.println("Override size: " + baseSize.x + "x" + baseSize.y);
-                }
-            } catch (RemoteException e) {
-            }
+            printInitialDisplaySize(pw, displayId);
+            return 0;
+        } else if ("-d".equals(size)) {
+            printInitialDisplaySize(pw, displayId);
             return 0;
         } else if ("reset".equals(size)) {
             w = h = -1;
@@ -114,8 +136,8 @@
             String wstr = size.substring(0, div);
             String hstr = size.substring(div+1);
             try {
-                w = parseDimension(wstr);
-                h = parseDimension(hstr);
+                w = parseDimension(wstr, displayId);
+                h = parseDimension(hstr, displayId);
             } catch (NumberFormatException e) {
                 getErrPrintWriter().println("Error: bad number " + e);
                 return -1;
@@ -123,27 +145,38 @@
         }
 
         if (w >= 0 && h >= 0) {
-            // TODO(multidisplay): For now Configuration only applies to main screen.
-            mInterface.setForcedDisplaySize(Display.DEFAULT_DISPLAY, w, h);
+            mInterface.setForcedDisplaySize(displayId, w, h);
         } else {
-            mInterface.clearForcedDisplaySize(Display.DEFAULT_DISPLAY);
+            mInterface.clearForcedDisplaySize(displayId);
         }
         return 0;
     }
 
+    private void printInitialDisplayDensity(PrintWriter pw , int displayId) {
+        try {
+            final int initialDensity = mInterface.getInitialDisplayDensity(displayId);
+            final int baseDensity = mInterface.getBaseDisplayDensity(displayId);
+            pw.println("Physical density: " + initialDensity);
+            if (initialDensity != baseDensity) {
+                pw.println("Override density: " + baseDensity);
+            }
+        } catch (RemoteException e) {
+            // Can't call getInitialDisplayDensity() on IWindowManager or
+            // Can't call getBaseDisplayDensity() on IWindowManager
+            pw.println("Remote exception: " + e);
+        }
+    }
+
     private int runDisplayDensity(PrintWriter pw) throws RemoteException {
         String densityStr = getNextArg();
         int density;
+        final int displayId = getDisplayId(densityStr);
+
         if (densityStr == null) {
-            try {
-                int initialDensity = mInterface.getInitialDisplayDensity(Display.DEFAULT_DISPLAY);
-                int baseDensity = mInterface.getBaseDisplayDensity(Display.DEFAULT_DISPLAY);
-                pw.println("Physical density: " + initialDensity);
-                if (initialDensity != baseDensity) {
-                    pw.println("Override density: " + baseDensity);
-                }
-            } catch (RemoteException e) {
-            }
+            printInitialDisplayDensity(pw, displayId);
+            return 0;
+        } else if ("-d".equals(densityStr)) {
+            printInitialDisplayDensity(pw, displayId);
             return 0;
         } else if ("reset".equals(densityStr)) {
             density = -1;
@@ -161,11 +194,10 @@
         }
 
         if (density > 0) {
-            // TODO(multidisplay): For now Configuration only applies to main screen.
-            mInterface.setForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY, density,
+            mInterface.setForcedDisplayDensityForUser(displayId, density,
                     UserHandle.USER_CURRENT);
         } else {
-            mInterface.clearForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY,
+            mInterface.clearForcedDisplayDensityForUser(displayId,
                     UserHandle.USER_CURRENT);
         }
         return 0;
@@ -174,6 +206,7 @@
     private int runDisplayOverscan(PrintWriter pw) throws RemoteException {
         String overscanStr = getNextArgRequired();
         Rect rect = new Rect();
+        final int displayId = getDisplayId(overscanStr);
         if ("reset".equals(overscanStr)) {
             rect.set(0, 0, 0, 0);
         } else {
@@ -190,17 +223,16 @@
             rect.bottom = Integer.parseInt(matcher.group(4));
         }
 
-        mInterface.setOverscan(Display.DEFAULT_DISPLAY, rect.left, rect.top, rect.right,
-                rect.bottom);
+        mInterface.setOverscan(displayId, rect.left, rect.top, rect.right, rect.bottom);
         return 0;
     }
 
     private int runDisplayScaling(PrintWriter pw) throws RemoteException {
         String scalingStr = getNextArgRequired();
         if ("auto".equals(scalingStr)) {
-            mInterface.setForcedDisplayScalingMode(Display.DEFAULT_DISPLAY, 0);
+            mInterface.setForcedDisplayScalingMode(getDisplayId(scalingStr), 0);
         } else if ("off".equals(scalingStr)) {
-            mInterface.setForcedDisplayScalingMode(Display.DEFAULT_DISPLAY, 1);
+            mInterface.setForcedDisplayScalingMode(getDisplayId(scalingStr), 1);
         } else {
             getErrPrintWriter().println("Error: scaling must be 'auto' or 'off'");
             return -1;
@@ -213,14 +245,14 @@
         return 0;
     }
 
-    private int parseDimension(String s) throws NumberFormatException {
+    private int parseDimension(String s, int displayId) throws NumberFormatException {
         if (s.endsWith("px")) {
             return Integer.parseInt(s.substring(0, s.length() - 2));
         }
         if (s.endsWith("dp")) {
             int density;
             try {
-                density = mInterface.getBaseDisplayDensity(Display.DEFAULT_DISPLAY);
+                density = mInterface.getBaseDisplayDensity(displayId);
             } catch (RemoteException e) {
                 density = DisplayMetrics.DENSITY_DEFAULT;
             }
@@ -236,14 +268,14 @@
         pw.println("Window manager (window) commands:");
         pw.println("  help");
         pw.println("      Print this help text.");
-        pw.println("  size [reset|WxH|WdpxHdp]");
+        pw.println("  size [reset|WxH|WdpxHdp] [-d DISPLAY_ID]");
         pw.println("    Return or override display size.");
         pw.println("    width and height in pixels unless suffixed with 'dp'.");
-        pw.println("  density [reset|DENSITY]");
+        pw.println("  density [reset|DENSITY] [-d DISPLAY_ID]");
         pw.println("    Return or override display density.");
-        pw.println("  overscan [reset|LEFT,TOP,RIGHT,BOTTOM]");
+        pw.println("  overscan [reset|LEFT,TOP,RIGHT,BOTTOM] [-d DISPLAY ID]");
         pw.println("    Set overscan area for display.");
-        pw.println("  scaling [off|auto]");
+        pw.println("  scaling [off|auto] [-d DISPLAY_ID]");
         pw.println("    Set display scaling mode.");
         pw.println("  dismiss-keyguard");
         pw.println("    Dismiss the keyguard, prompting user for auth if necessary.");
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 5272b66..f7c6d77 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -304,6 +304,8 @@
      */
     private final MergedConfiguration mLastReportedConfiguration = new MergedConfiguration();
 
+    private final Configuration mTempConfiguration = new Configuration();
+
     /**
      * The last content insets returned to the client in relayout. We use
      * these in the bounds animation to ensure we only observe inset changes
@@ -359,8 +361,6 @@
      */
     private final Rect mInsetFrame = new Rect();
 
-    boolean mContentChanged;
-
     // If a window showing a wallpaper: the requested offset for the
     // wallpaper; if a wallpaper window: the currently applied offset.
     float mWallpaperX = -1;
@@ -593,14 +593,14 @@
 
         if (mForceSeamlesslyRotate || requested) {
             mPendingSeamlessRotate = new SeamlessRotator(oldRotation, rotation, getDisplayInfo());
-            mPendingSeamlessRotate.unrotate(transaction, this.mToken);
+            mPendingSeamlessRotate.unrotate(transaction, this);
             mService.markForSeamlessRotation(this, true);
         }
     }
 
     void finishSeamlessRotation() {
         if (mPendingSeamlessRotate != null) {
-            mPendingSeamlessRotate.finish(this.mToken, this);
+            mPendingSeamlessRotate.finish(this);
             mFinishSeamlessRotateFrameNumber = getFrameNumber();
             mPendingSeamlessRotate = null;
             mService.markForSeamlessRotation(this, false);
@@ -787,7 +787,7 @@
     }
 
     @Override
-    public void computeFrameLw(WindowFrames windowFrames) {
+    public void computeFrameLw() {
         if (mWillReplaceWindow && (mAnimatingExit || !mReplacingRemoveRequested)) {
             // This window is being replaced and either already got information that it's being
             // removed or we are still waiting for some information. Because of this we don't
@@ -796,8 +796,6 @@
             return;
         }
         mHaveFrame = true;
-        mWindowFrames.setParentFrameWasClippedByDisplayCutout(
-                windowFrames.parentFrameWasClippedByDisplayCutout());
 
         final Task task = getTask();
         final boolean inFullscreenContainer = inFullscreenContainer();
@@ -827,10 +825,9 @@
         final int layoutYDiff;
         if (inFullscreenContainer || layoutInParentFrame()) {
             // We use the parent frame as the containing frame for fullscreen and child windows
-            mWindowFrames.mContainingFrame.set(windowFrames.mParentFrame);
-            mWindowFrames.mDisplayFrame.set(windowFrames.mDisplayFrame);
-            layoutDisplayFrame = windowFrames.mDisplayFrame;
-            layoutContainingFrame = windowFrames.mParentFrame;
+            mWindowFrames.mContainingFrame.set(mWindowFrames.mParentFrame);
+            layoutDisplayFrame = mWindowFrames.mDisplayFrame;
+            layoutContainingFrame = mWindowFrames.mParentFrame;
             layoutXDiff = 0;
             layoutYDiff = 0;
         } else {
@@ -849,17 +846,17 @@
             // IME is up and obscuring this window. Adjust the window position so it is visible.
             if (imeWin != null && imeWin.isVisibleNow() && isInputMethodTarget()) {
                 if (inFreeformWindowingMode() && mWindowFrames.mContainingFrame.bottom
-                        > windowFrames.mContentFrame.bottom) {
+                        > mWindowFrames.mContentFrame.bottom) {
                     // In freeform we want to move the top up directly.
                     // TODO: Investigate why this is contentFrame not parentFrame.
                     mWindowFrames.mContainingFrame.top -= mWindowFrames.mContainingFrame.bottom
-                            - windowFrames.mContentFrame.bottom;
+                            - mWindowFrames.mContentFrame.bottom;
                 } else if (!inPinnedWindowingMode() && mWindowFrames.mContainingFrame.bottom
-                        > windowFrames.mParentFrame.bottom) {
+                        > mWindowFrames.mParentFrame.bottom) {
                     // But in docked we want to behave like fullscreen and behave as if the task
                     // were given smaller bounds for the purposes of layout. Skip adjustments for
                     // the pinned stack, they are handled separately in the PinnedStackController.
-                    mWindowFrames.mContainingFrame.bottom = windowFrames.mParentFrame.bottom;
+                    mWindowFrames.mContainingFrame.bottom = mWindowFrames.mParentFrame.bottom;
                 }
             }
 
@@ -868,7 +865,7 @@
                 // if it wasn't set already. No need to intersect it with the (visible)
                 // "content frame" since it is allowed to be outside the visible desktop.
                 if (mWindowFrames.mContainingFrame.isEmpty()) {
-                    mWindowFrames.mContainingFrame.set(windowFrames.mContentFrame);
+                    mWindowFrames.mContainingFrame.set(mWindowFrames.mContentFrame);
                 }
             }
 
@@ -878,10 +875,11 @@
                 // PIP edge case: When going from pinned to fullscreen, we apply a
                 // tempInsetFrame for the full task - but we're still at the start of the animation.
                 // To prevent a jump if there's a letterbox, restrict to the parent frame.
-                mInsetFrame.intersectUnchecked(windowFrames.mParentFrame);
-                mWindowFrames.mContainingFrame.intersectUnchecked(windowFrames.mParentFrame);
+                mInsetFrame.intersectUnchecked(mWindowFrames.mParentFrame);
+                mWindowFrames.mContainingFrame.intersectUnchecked(mWindowFrames.mParentFrame);
             }
 
+            layoutDisplayFrame = new Rect(mWindowFrames.mDisplayFrame);
             mWindowFrames.mDisplayFrame.set(mWindowFrames.mContainingFrame);
             layoutXDiff =
                     !mInsetFrame.isEmpty() ? mInsetFrame.left - mWindowFrames.mContainingFrame.left
@@ -892,41 +890,24 @@
             layoutContainingFrame =
                     !mInsetFrame.isEmpty() ? mInsetFrame : mWindowFrames.mContainingFrame;
             mTmpRect.set(0, 0, dc.getDisplayInfo().logicalWidth, dc.getDisplayInfo().logicalHeight);
-            subtractInsets(mWindowFrames.mDisplayFrame, layoutContainingFrame,
-                    windowFrames.mDisplayFrame, mTmpRect);
+            subtractInsets(mWindowFrames.mDisplayFrame, layoutContainingFrame, layoutDisplayFrame,
+                    mTmpRect);
             if (!layoutInParentFrame()) {
                 subtractInsets(mWindowFrames.mContainingFrame, layoutContainingFrame,
-                        windowFrames.mParentFrame, mTmpRect);
-                subtractInsets(mInsetFrame, layoutContainingFrame, windowFrames.mParentFrame,
+                        mWindowFrames.mParentFrame, mTmpRect);
+                subtractInsets(mInsetFrame, layoutContainingFrame, mWindowFrames.mParentFrame,
                         mTmpRect);
             }
-            layoutDisplayFrame = windowFrames.mDisplayFrame;
             layoutDisplayFrame.intersect(layoutContainingFrame);
         }
 
         final int pw = mWindowFrames.mContainingFrame.width();
         final int ph = mWindowFrames.mContainingFrame.height();
 
-        if (!mWindowFrames.mParentFrame.equals(windowFrames.mParentFrame)) {
-            //Slog.i(TAG_WM, "Window " + this + " content frame from " + mParentFrame
-            //        + " to " + parentFrame);
-            mWindowFrames.mParentFrame.set(windowFrames.mParentFrame);
-            mContentChanged = true;
-        }
         if (mRequestedWidth != mLastRequestedWidth || mRequestedHeight != mLastRequestedHeight) {
             mLastRequestedWidth = mRequestedWidth;
             mLastRequestedHeight = mRequestedHeight;
-            mContentChanged = true;
-        }
-
-        mWindowFrames.mOverscanFrame.set(windowFrames.mOverscanFrame);
-        mWindowFrames.mContentFrame.set(windowFrames.mContentFrame);
-        mWindowFrames.mVisibleFrame.set(windowFrames.mVisibleFrame);
-        mWindowFrames.mDecorFrame.set(windowFrames.mDecorFrame);
-        mWindowFrames.mStableFrame.set(windowFrames.mStableFrame);
-        final boolean hasOutsets = !windowFrames.mOutsetFrame.isEmpty();
-        if (hasOutsets) {
-            mWindowFrames.mOutsetFrame.set(windowFrames.mOutsetFrame);
+            mWindowFrames.setContentChanged(true);
         }
 
         final int fw = mWindowFrames.mFrame.width();
@@ -935,7 +916,7 @@
         applyGravityAndUpdateFrame(layoutContainingFrame, layoutDisplayFrame);
 
         // Calculate the outsets before the content frame gets shrinked to the window frame.
-        mWindowFrames.calculateOutsets(hasOutsets);
+        mWindowFrames.calculateOutsets();
 
         // Make sure the content and visible frames are inside of the
         // final window frame.
@@ -997,7 +978,7 @@
         }
 
         if (mAttrs.type == TYPE_DOCK_DIVIDER) {
-            final WmDisplayCutout c = windowFrames.mDisplayCutout.calculateRelativeTo(
+            final WmDisplayCutout c = mWindowFrames.mDisplayCutout.calculateRelativeTo(
                     mWindowFrames.mDisplayFrame);
             mWindowFrames.calculateDockedDividerInsets(c.getDisplayCutout().getSafeInsets());
         } else {
@@ -1006,7 +987,7 @@
         }
 
         mWindowFrames.setDisplayCutout(
-                windowFrames.mDisplayCutout.calculateRelativeTo(mWindowFrames.mFrame));
+                mWindowFrames.mDisplayCutout.calculateRelativeTo(mWindowFrames.mFrame));
 
         // Offset the actual frame by the amount layout frame is off.
         mWindowFrames.offsetFrames(-layoutXDiff, -layoutYDiff);
@@ -1280,6 +1261,7 @@
 
     @Override
     void onDisplayChanged(DisplayContent dc) {
+        updateSurfaceSize(dc);
         super.onDisplayChanged(dc);
         // Window was not laid out for this display yet, so make sure mLayoutSeq does not match.
         if (dc != null) {
@@ -1733,7 +1715,7 @@
      * sense to call from performLayoutAndPlaceSurfacesLockedInner().)
      */
     private boolean hasMoved() {
-        return mHasSurface && (mContentChanged || mMovedByResize)
+        return mHasSurface && (mWindowFrames.hasContentChanged() || mMovedByResize)
                 && !mAnimatingExit
                 && (mWindowFrames.mFrame.top != mWindowFrames.mLastFrame.top
                     || mWindowFrames.mFrame.left != mWindowFrames.mLastFrame.left)
@@ -2270,8 +2252,17 @@
         }
     }
 
+    private Configuration getProcessGlobalConfiguration() {
+        // For child windows we want to use the pid for the parent window in case the the child
+        // window was added from another process.
+        final int pid = isChildWindow() ? getParentWindow().mSession.mPid : mSession.mPid;
+        mTempConfiguration.setTo(mService.mProcessConfigurations.get(
+                pid, mService.mRoot.getConfiguration()));
+        return mTempConfiguration;
+    }
+
     void getMergedConfiguration(MergedConfiguration outConfiguration) {
-        final Configuration globalConfig = mService.mRoot.getConfiguration();
+        final Configuration globalConfig = getProcessGlobalConfiguration();
         final Configuration overrideConfig = getMergedOverrideConfiguration();
         outConfiguration.setConfiguration(globalConfig, overrideConfig);
     }
@@ -2874,7 +2865,11 @@
             return mAppToken.mFrozenMergedConfig.peek();
         }
 
-        return super.getConfiguration();
+        // We use the process config this window is associated with as the based global config since
+        // the process can override it config, but isn't part of the window hierarchy.
+        final Configuration config = getProcessGlobalConfiguration();
+        config.updateFrom(getMergedOverrideConfiguration());
+        return config;
     }
 
     void reportResized() {
@@ -4540,7 +4535,8 @@
         updateSurfacePosition(getPendingTransaction());
     }
 
-    private void updateSurfacePosition(Transaction t) {
+    @VisibleForTesting
+    void updateSurfacePosition(Transaction t) {
         if (mSurfaceControl == null) {
             return;
         }
@@ -4762,6 +4758,15 @@
         return mWindowFrames.mVisibleInsets;
     }
 
+    @Override
+    public WindowFrames getWindowFrames() {
+        return mWindowFrames;
+    }
+
+    void resetContentChanged() {
+        mWindowFrames.setContentChanged(false);
+    }
+
     private final class MoveAnimationSpec implements AnimationSpec {
 
         private final long mDuration;
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index fec8039..979149a 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1176,15 +1176,17 @@
                         if (mIsWallpaper) {
                             w.dispatchWallpaperVisibility(true);
                         }
-                        // This draw means the difference between unique content and mirroring.
-                        // Run another pass through performLayout to set mHasContent in the
-                        // LogicalDisplay.
-                        mAnimator.setPendingLayoutChanges(w.getDisplayId(),
-                                FINISH_LAYOUT_REDO_ANIM);
-                        if (DEBUG_LAYOUT_REPEATS) {
-                            mService.mWindowPlacerLocked.debugLayoutRepeats(
-                                    "showSurfaceRobustlyLocked " + w,
-                                    mAnimator.getPendingLayoutChanges(w.getDisplayId()));
+                        if (!w.getDisplayContent().getLastHasContent()) {
+                            // This draw means the difference between unique content and mirroring.
+                            // Run another pass through performLayout to set mHasContent in the
+                            // LogicalDisplay.
+                            mAnimator.setPendingLayoutChanges(w.getDisplayId(),
+                                    FINISH_LAYOUT_REDO_ANIM);
+                            if (DEBUG_LAYOUT_REPEATS) {                        
+                                mService.mWindowPlacerLocked.debugLayoutRepeats(
+                                        "showSurfaceRobustlyLocked " + w,
+                                        mAnimator.getPendingLayoutChanges(w.getDisplayId()));
+                            }
                         }
                     } else {
                         w.setOrientationChanging(false);
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index d6f9ac3..c8d1a8b 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -92,9 +92,8 @@
 
     static final int SET_UPDATE_ROTATION                = 1 << 0;
     static final int SET_WALLPAPER_MAY_CHANGE           = 1 << 1;
-    static final int SET_FORCE_HIDING_CHANGED           = 1 << 2;
-    static final int SET_ORIENTATION_CHANGE_COMPLETE    = 1 << 3;
-    static final int SET_WALLPAPER_ACTION_PENDING       = 1 << 4;
+    static final int SET_ORIENTATION_CHANGE_COMPLETE    = 1 << 2;
+    static final int SET_WALLPAPER_ACTION_PENDING       = 1 << 3;
 
     private boolean mTraversalScheduled;
     private int mDeferDepth = 0;
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index e411c0a..8972c38 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -18,6 +18,7 @@
 
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
+
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
@@ -275,6 +276,7 @@
         // to another display before the window behind
         // it is ready.
 
+        updateSurfaceSize(dc);
         super.onDisplayChanged(dc);
     }
 
diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp
index 93c4829..6c2a894 100644
--- a/services/core/jni/com_android_server_tv_TvInputHal.cpp
+++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp
@@ -390,7 +390,11 @@
                 [&result, &sidebandStream](Result res, const native_handle_t* handle) {
                     result = res;
                     if (res == Result::OK) {
-                        sidebandStream = handle;
+                        if (handle) {
+                            sidebandStream = native_handle_clone(handle);
+                        } else {
+                            result = Result::UNKNOWN;
+                        }
                     }
                 });
         if (result != Result::OK) {
@@ -398,7 +402,7 @@
                     result);
             return UNKNOWN_ERROR;
         }
-        connection.mSourceHandle = NativeHandle::create((native_handle_t*)sidebandStream, false);
+        connection.mSourceHandle = NativeHandle::create((native_handle_t*)sidebandStream, true);
     }
     connection.mSurface = surface;
     if (connection.mSurface != nullptr) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 0ca0835..e76afa3 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2588,12 +2588,32 @@
 
     ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
             throws SecurityException {
+        return getActiveAdminOrCheckPermissionForCallerLocked(who,
+                reqPolicy, /* permission= */ null);
+    }
+
+    /**
+     * Finds an active admin for the caller then checks {@code permission} if admin check failed.
+     *
+     * @return an active admin or {@code null} if there is no active admin but
+     * {@code permission} is granted
+     * @throws SecurityException if caller neither has an active admin nor {@code permission}
+     */
+    @Nullable
+    ActiveAdmin getActiveAdminOrCheckPermissionForCallerLocked(
+            ComponentName who,
+            int reqPolicy,
+            @Nullable String permission) throws SecurityException {
         ensureLocked();
         final int callingUid = mInjector.binderGetCallingUid();
 
         ActiveAdmin result = getActiveAdminWithPolicyForUidLocked(who, reqPolicy, callingUid);
         if (result != null) {
             return result;
+        } else if (permission != null
+                && (mContext.checkCallingPermission(permission)
+                        == PackageManager.PERMISSION_GRANTED)) {
+            return null;
         }
 
         if (who != null) {
@@ -2605,7 +2625,7 @@
 
             if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) {
                 throw new SecurityException("Admin " + admin.info.getComponent()
-                         + " does not own the device");
+                        + " does not own the device");
             }
             if (reqPolicy == DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) {
                 throw new SecurityException("Admin " + admin.info.getComponent()
@@ -2621,20 +2641,39 @@
                     + admin.info.getTagForPolicy(reqPolicy));
         } else {
             throw new SecurityException("No active admin owned by uid "
-                    + mInjector.binderGetCallingUid() + " for policy #" + reqPolicy);
+                    + callingUid + " for policy #" + reqPolicy);
         }
     }
 
     ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy, boolean parent)
             throws SecurityException {
+        return getActiveAdminOrCheckPermissionForCallerLocked(
+                who, reqPolicy, parent, /* permission= */ null);
+    }
+
+    /**
+     * Finds an active admin for the caller then checks {@code permission} if admin check failed.
+     *
+     * @return an active admin or {@code null} if there is no active admin but
+     * {@code permission} is granted
+     * @throws SecurityException if caller neither has an active admin nor {@code permission}
+     */
+    @Nullable
+    ActiveAdmin getActiveAdminOrCheckPermissionForCallerLocked(
+            ComponentName who,
+            int reqPolicy,
+            boolean parent,
+            @Nullable String permission) throws SecurityException {
         ensureLocked();
         if (parent) {
             enforceManagedProfile(mInjector.userHandleGetCallingUserId(),
                     "call APIs on the parent profile");
         }
-        ActiveAdmin admin = getActiveAdminForCallerLocked(who, reqPolicy);
+        ActiveAdmin admin = getActiveAdminOrCheckPermissionForCallerLocked(
+                who, reqPolicy, permission);
         return parent ? admin.getParentActiveAdmin() : admin;
     }
+
     /**
      * Find the admin for the component and userId bit of the uid, then check
      * the admin's uid matches the uid.
@@ -4744,10 +4783,15 @@
                 preN = getTargetSdk(admin.info.getPackageName(),
                         userHandle) <= android.os.Build.VERSION_CODES.M;
             } else {
-                // Otherwise, make sure the caller has any active admin with the right policy.
-                admin = getActiveAdminForCallerLocked(null,
-                        DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
-                preN = getTargetSdk(admin.info.getPackageName(),
+                // Otherwise, make sure the caller has any active admin with the right policy or
+                // the required permission.
+                admin = getActiveAdminOrCheckPermissionForCallerLocked(
+                        null,
+                        DeviceAdminInfo.USES_POLICY_RESET_PASSWORD,
+                        android.Manifest.permission.RESET_PASSWORD);
+                // Cannot be preN if admin is null because an exception would have been
+                // thrown before getting here
+                preN = admin == null ? false : getTargetSdk(admin.info.getPackageName(),
                         userHandle) <= android.os.Build.VERSION_CODES.M;
 
                 // As of N, password resetting to empty/null is not allowed anymore.
@@ -4763,9 +4807,9 @@
                 // As of N, password cannot be changed by the admin if it is already set.
                 if (isLockScreenSecureUnchecked(userHandle)) {
                     if (!preN) {
-                        throw new SecurityException("Admin cannot change current password");
+                        throw new SecurityException("Cannot change current password");
                     } else {
-                        Slog.e(LOG_TAG, "Admin cannot change current password");
+                        Slog.e(LOG_TAG, "Cannot change current password");
                         return false;
                     }
                 }
@@ -5136,31 +5180,37 @@
 
         final int callingUserId = mInjector.userHandleGetCallingUserId();
         synchronized (getLockObject()) {
-            // This API can only be called by an active device admin,
-            // so try to retrieve it to check that the caller is one.
-            final ActiveAdmin admin = getActiveAdminForCallerLocked(
-                    null, DeviceAdminInfo.USES_POLICY_FORCE_LOCK, parent);
-
+            // Make sure the caller has any active admin with the right policy or
+            // the required permission.
+            final ActiveAdmin admin = getActiveAdminOrCheckPermissionForCallerLocked(
+                    null,
+                    DeviceAdminInfo.USES_POLICY_FORCE_LOCK,
+                    parent,
+                    android.Manifest.permission.LOCK_DEVICE);
             final long ident = mInjector.binderClearCallingIdentity();
             try {
-                final ComponentName adminComponent = admin.info.getComponent();
-                // Evict key
-                if ((flags & DevicePolicyManager.FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY) != 0) {
-                    enforceManagedProfile(
-                            callingUserId, "set FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY");
-                    if (!isProfileOwner(adminComponent, callingUserId)) {
-                        throw new SecurityException("Only profile owner admins can set "
-                                + "FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY");
+                final ComponentName adminComponent = admin == null ?
+                        null : admin.info.getComponent();
+                if (adminComponent != null) {
+                    // For Profile Owners only, callers with only permission not allowed.
+                    if ((flags & DevicePolicyManager.FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY) != 0) {
+                        // Evict key
+                        enforceManagedProfile(
+                                callingUserId, "set FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY");
+                        if (!isProfileOwner(adminComponent, callingUserId)) {
+                            throw new SecurityException("Only profile owner admins can set "
+                                    + "FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY");
+                        }
+                        if (parent) {
+                            throw new IllegalArgumentException(
+                                    "Cannot set FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY for the parent");
+                        }
+                        if (!mInjector.storageManagerIsFileBasedEncryptionEnabled()) {
+                            throw new UnsupportedOperationException(
+                                    "FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY only applies to FBE devices");
+                        }
+                        mUserManager.evictCredentialEncryptionKey(callingUserId);
                     }
-                    if (parent) {
-                        throw new IllegalArgumentException(
-                                "Cannot set FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY for the parent");
-                    }
-                    if (!mInjector.storageManagerIsFileBasedEncryptionEnabled()) {
-                        throw new UnsupportedOperationException(
-                                "FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY only applies to FBE devices");
-                    }
-                    mUserManager.evictCredentialEncryptionKey(callingUserId);
                 }
 
                 // Lock all users unless this is a managed profile with a separate challenge
@@ -5179,7 +5229,7 @@
                     mInjector.getTrustManager().setDeviceLockedForUser(userToLock, true);
                 }
 
-                if (SecurityLog.isLoggingEnabled()) {
+                if (SecurityLog.isLoggingEnabled() && adminComponent != null) {
                     final int affectedUserId =
                             parent ? getProfileParentId(callingUserId) : callingUserId;
                     SecurityLog.writeEvent(SecurityLog.TAG_REMOTE_LOCK,
@@ -5969,7 +6019,7 @@
             success = mUserManagerInternal.removeUserEvenWhenDisallowed(userId);
             if (!success) {
                 Slog.w(LOG_TAG, "Couldn't remove user " + userId);
-            } else if (isManagedProfile(userId)) {
+            } else if (isManagedProfile(userId) && !TextUtils.isEmpty(wipeReasonForUser)) {
                 sendWipeProfileNotification(wipeReasonForUser);
             }
         } catch (RemoteException re) {
@@ -5984,7 +6034,6 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkStringNotEmpty(wipeReasonForUser, "wipeReasonForUser is null or empty");
         enforceFullCrossUsersPermission(mInjector.userHandleGetCallingUserId());
 
         final ActiveAdmin admin;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index c80b9d8..b8241d0 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -63,11 +63,11 @@
 import com.android.internal.util.ConcurrentUtils;
 import com.android.internal.util.EmergencyAffordanceManager;
 import com.android.internal.widget.ILockSettings;
-import com.android.server.accessibility.AccessibilityManagerService;
 import com.android.server.am.ActivityManagerService;
 import com.android.server.am.ActivityTaskManagerService;
+import com.android.server.appbinding.AppBindingService;
 import com.android.server.audio.AudioService;
-import com.android.server.biometrics.BiometricPromptService;
+import com.android.server.biometrics.BiometricService;
 import com.android.server.broadcastradio.BroadcastRadioService;
 import com.android.server.camera.CameraServiceProxy;
 import com.android.server.clipboard.ClipboardService;
@@ -118,6 +118,7 @@
 import com.android.server.storage.DeviceStorageMonitorService;
 import com.android.server.telecom.TelecomLoaderService;
 import com.android.server.textclassifier.TextClassificationManagerService;
+import com.android.server.textservices.TextServicesManagerService;
 import com.android.server.trust.TrustManagerService;
 import com.android.server.tv.TvInputManagerService;
 import com.android.server.tv.TvRemoteService;
@@ -785,6 +786,8 @@
 
         boolean disableSystemTextClassifier = SystemProperties.getBoolean(
                 "config.disable_systemtextclassifier", false);
+        boolean disableNetworkTime = SystemProperties.getBoolean("config.disable_networktime",
+                false);
         boolean disableCameraService = SystemProperties.getBoolean("config.disable_cameraservice",
                 false);
         boolean disableSlices = SystemProperties.getBoolean("config.disable_slices", false);
@@ -795,6 +798,9 @@
         boolean isWatch = context.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_WATCH);
 
+        boolean enableVrService = context.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE);
+
         // For debugging RescueParty
         if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.crash_system", false)) {
             throw new RuntimeException();
@@ -928,7 +934,7 @@
                 traceLog.traceEnd();
             }, START_HIDL_SERVICES);
 
-            if (!isWatch) {
+            if (!isWatch && enableVrService) {
                 traceBeginAndSlog("StartVrManagerService");
                 mSystemServiceManager.startService(VrManagerService.class);
                 traceEnd();
@@ -1459,7 +1465,7 @@
                 traceEnd();
             }
 
-            if (!isWatch) {
+            if (!isWatch && !disableNetworkTime) {
                 traceBeginAndSlog("StartNetworkTimeUpdateService");
                 try {
                     if (useNewTimeServices) {
@@ -1584,7 +1590,7 @@
             if (hasFeatureFace || hasFeatureFingerprint) {
                 // Start this service after all biometric services.
                 traceBeginAndSlog("StartBiometricPromptService");
-                mSystemServiceManager.startService(BiometricPromptService.class);
+                mSystemServiceManager.startService(BiometricService.class);
                 traceEnd();
             }
 
@@ -1705,6 +1711,10 @@
             traceEnd();
         }
 
+        traceBeginAndSlog("AppServiceManager");
+        mSystemServiceManager.startService(AppBindingService.Lifecycle.class);
+        traceEnd();
+
         // It is now time to start up the app processes...
 
         traceBeginAndSlog("MakeVibratorServiceReady");
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/net/java/android/net/ip/IpServer.java
similarity index 89%
rename from services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
rename to services/net/java/android/net/ip/IpServer.java
index 5accb45..823c0a1 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/net/java/android/net/ip/IpServer.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.connectivity.tethering;
+package android.net.ip;
 
 import static android.net.NetworkUtils.numericToInetAddress;
 import static android.net.util.NetworkConstants.asByte;
@@ -31,11 +31,10 @@
 import android.net.RouteInfo;
 import android.net.dhcp.DhcpServer;
 import android.net.dhcp.DhcpServingParams;
-import android.net.ip.InterfaceController;
-import android.net.ip.RouterAdvertisementDaemon;
 import android.net.ip.RouterAdvertisementDaemon.RaParams;
 import android.net.util.InterfaceParams;
 import android.net.util.InterfaceSet;
+import android.net.util.NetdService;
 import android.net.util.SharedLog;
 import android.os.INetworkManagementService;
 import android.os.Looper;
@@ -67,7 +66,22 @@
  *
  * @hide
  */
-public class TetherInterfaceStateMachine extends StateMachine {
+public class IpServer extends StateMachine {
+    public static final int STATE_UNAVAILABLE = 0;
+    public static final int STATE_AVAILABLE   = 1;
+    public static final int STATE_TETHERED    = 2;
+    public static final int STATE_LOCAL_ONLY  = 3;
+
+    public static String getStateString(int state) {
+        switch (state) {
+            case STATE_UNAVAILABLE: return "UNAVAILABLE";
+            case STATE_AVAILABLE:   return "AVAILABLE";
+            case STATE_TETHERED:    return "TETHERED";
+            case STATE_LOCAL_ONLY:  return "LOCAL_ONLY";
+        }
+        return "UNKNOWN: " + state;
+    }
+
     private static final IpPrefix LINK_LOCAL_PREFIX = new IpPrefix("fe80::/64");
     private static final byte DOUG_ADAMS = (byte) 42;
 
@@ -83,15 +97,53 @@
     // TODO: have this configurable
     private static final int DHCP_LEASE_TIME_SECS = 3600;
 
-    private final static String TAG = "TetherInterfaceSM";
+    private final static String TAG = "IpServer";
     private final static boolean DBG = false;
     private final static boolean VDBG = false;
     private static final Class[] messageClasses = {
-            TetherInterfaceStateMachine.class
+            IpServer.class
     };
     private static final SparseArray<String> sMagicDecoderRing =
             MessageUtils.findMessageNames(messageClasses);
 
+    public static class Callback {
+        /**
+         * Notify that |who| has changed its tethering state.
+         *
+         * @param who the calling instance of IpServer
+         * @param state one of STATE_*
+         * @param lastError one of ConnectivityManager.TETHER_ERROR_*
+         */
+        public void updateInterfaceState(IpServer who, int state, int lastError) {}
+
+        /**
+         * Notify that |who| has new LinkProperties.
+         *
+         * @param who the calling instance of IpServer
+         * @param newLp the new LinkProperties to report
+         */
+        public void updateLinkProperties(IpServer who, LinkProperties newLp) {}
+    }
+
+    public static class Dependencies {
+        public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) {
+            return new RouterAdvertisementDaemon(ifParams);
+        }
+
+        public InterfaceParams getInterfaceParams(String ifName) {
+            return InterfaceParams.getByName(ifName);
+        }
+
+        public INetd getNetdService() {
+            return NetdService.getInstance();
+        }
+
+        public DhcpServer makeDhcpServer(Looper looper, InterfaceParams iface,
+                DhcpServingParams params, SharedLog log) {
+            return new DhcpServer(looper, iface, params, log);
+        }
+    }
+
     private static final int BASE_IFACE              = Protocol.BASE_TETHERING + 100;
     // request from the user that it wants to tether
     public static final int CMD_TETHER_REQUESTED            = BASE_IFACE + 2;
@@ -123,7 +175,7 @@
     private final INetworkManagementService mNMService;
     private final INetd mNetd;
     private final INetworkStatsService mStatsService;
-    private final IControlsTethering mTetherController;
+    private final Callback mCallback;
     private final InterfaceController mInterfaceCtrl;
 
     private final String mIfaceName;
@@ -131,7 +183,7 @@
     private final LinkProperties mLinkProperties;
     private final boolean mUsingLegacyDhcp;
 
-    private final TetheringDependencies mDeps;
+    private final Dependencies mDeps;
 
     private int mLastError;
     private int mServingMode;
@@ -148,17 +200,16 @@
     private DhcpServer mDhcpServer;
     private RaParams mLastRaParams;
 
-    public TetherInterfaceStateMachine(
+    public IpServer(
             String ifaceName, Looper looper, int interfaceType, SharedLog log,
             INetworkManagementService nMService, INetworkStatsService statsService,
-            IControlsTethering tetherController, boolean usingLegacyDhcp,
-            TetheringDependencies deps) {
+            Callback callback, boolean usingLegacyDhcp, Dependencies deps) {
         super(ifaceName, looper);
         mLog = log.forSubComponent(ifaceName);
         mNMService = nMService;
         mNetd = deps.getNetdService();
         mStatsService = statsService;
-        mTetherController = tetherController;
+        mCallback = callback;
         mInterfaceCtrl = new InterfaceController(ifaceName, nMService, mNetd, mLog);
         mIfaceName = ifaceName;
         mInterfaceType = interfaceType;
@@ -167,7 +218,7 @@
         mDeps = deps;
         resetLinkProperties();
         mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
-        mServingMode = IControlsTethering.STATE_AVAILABLE;
+        mServingMode = STATE_AVAILABLE;
 
         mInitialState = new InitialState();
         mLocalHotspotState = new LocalHotspotState();
@@ -379,6 +430,8 @@
             params.mtu = v6only.getMtu();
             params.hasDefaultRoute = v6only.hasIPv6DefaultRoute();
 
+            if (params.hasDefaultRoute) params.hopLimit = getHopLimit(v6only.getInterfaceName());
+
             for (LinkAddress linkAddr : v6only.getLinkAddresses()) {
                 if (linkAddr.getPrefixLength() != RFC7421_PREFIX_LENGTH) continue;
 
@@ -498,6 +551,20 @@
         }
     }
 
+    private byte getHopLimit(String upstreamIface) {
+        try {
+            int upstreamHopLimit = Integer.parseUnsignedInt(
+                    mNetd.getProcSysNet(INetd.IPV6, INetd.CONF, upstreamIface, "hop_limit"));
+            // Add one hop to account for this forwarding device
+            upstreamHopLimit++;
+            // Cap the hop limit to 255.
+            return (byte) Integer.min(upstreamHopLimit, 255);
+        } catch (Exception e) {
+            mLog.e("Failed to find upstream interface hop limit", e);
+        }
+        return RaParams.DEFAULT_HOPLIMIT;
+    }
+
     private void setRaParams(RaParams newParams) {
         if (mRaDaemon != null) {
             final RaParams deprecatedParams =
@@ -521,14 +588,12 @@
 
     private void sendInterfaceState(int newInterfaceState) {
         mServingMode = newInterfaceState;
-        mTetherController.updateInterfaceState(
-                TetherInterfaceStateMachine.this, newInterfaceState, mLastError);
+        mCallback.updateInterfaceState(this, newInterfaceState, mLastError);
         sendLinkProperties();
     }
 
     private void sendLinkProperties() {
-        mTetherController.updateLinkProperties(
-                TetherInterfaceStateMachine.this, new LinkProperties(mLinkProperties));
+        mCallback.updateLinkProperties(this, new LinkProperties(mLinkProperties));
     }
 
     private void resetLinkProperties() {
@@ -539,7 +604,7 @@
     class InitialState extends State {
         @Override
         public void enter() {
-            sendInterfaceState(IControlsTethering.STATE_AVAILABLE);
+            sendInterfaceState(STATE_AVAILABLE);
         }
 
         @Override
@@ -549,10 +614,10 @@
                 case CMD_TETHER_REQUESTED:
                     mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
                     switch (message.arg1) {
-                        case IControlsTethering.STATE_LOCAL_ONLY:
+                        case STATE_LOCAL_ONLY:
                             transitionTo(mLocalHotspotState);
                             break;
-                        case IControlsTethering.STATE_TETHERED:
+                        case STATE_TETHERED:
                             transitionTo(mTetheredState);
                             break;
                         default:
@@ -649,7 +714,7 @@
     // problematic because transitioning during a multi-state jump yields
     // a Log.wtf(). Ultimately, there should be only one ServingState,
     // and forwarding and NAT rules should be handled by a coordinating
-    // functional element outside of TetherInterfaceStateMachine.
+    // functional element outside of IpServer.
     class LocalHotspotState extends BaseServingState {
         @Override
         public void enter() {
@@ -659,7 +724,7 @@
             }
 
             if (DBG) Log.d(TAG, "Local hotspot " + mIfaceName);
-            sendInterfaceState(IControlsTethering.STATE_LOCAL_ONLY);
+            sendInterfaceState(STATE_LOCAL_ONLY);
         }
 
         @Override
@@ -685,7 +750,7 @@
     // problematic because transitioning during a multi-state jump yields
     // a Log.wtf(). Ultimately, there should be only one ServingState,
     // and forwarding and NAT rules should be handled by a coordinating
-    // functional element outside of TetherInterfaceStateMachine.
+    // functional element outside of IpServer.
     class TetheredState extends BaseServingState {
         @Override
         public void enter() {
@@ -695,7 +760,7 @@
             }
 
             if (DBG) Log.d(TAG, "Tethered " + mIfaceName);
-            sendInterfaceState(IControlsTethering.STATE_TETHERED);
+            sendInterfaceState(STATE_TETHERED);
         }
 
         @Override
@@ -817,7 +882,7 @@
         @Override
         public void enter() {
             mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
-            sendInterfaceState(IControlsTethering.STATE_UNAVAILABLE);
+            sendInterfaceState(STATE_UNAVAILABLE);
         }
     }
 
diff --git a/services/net/java/android/net/netlink/InetDiagMessage.java b/services/net/java/android/net/netlink/InetDiagMessage.java
new file mode 100644
index 0000000..af9e601
--- /dev/null
+++ b/services/net/java/android/net/netlink/InetDiagMessage.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.netlink;
+
+import static android.os.Process.INVALID_UID;
+import static android.net.netlink.NetlinkConstants.SOCK_DIAG_BY_FAMILY;
+import static android.net.netlink.NetlinkSocket.DEFAULT_RECV_BUFSIZE;
+import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
+import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.IPPROTO_UDP;
+import static android.system.OsConstants.NETLINK_INET_DIAG;
+
+import android.os.Build;
+import android.os.Process;
+import android.system.ErrnoException;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.InterruptedIOException;
+import java.net.DatagramSocket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetSocketAddress;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * A NetlinkMessage subclass for netlink inet_diag messages.
+ *
+ * see also: &lt;linux_src&gt;/include/uapi/linux/inet_diag.h
+ *
+ * @hide
+ */
+public class InetDiagMessage extends NetlinkMessage {
+    public static final String TAG = "InetDiagMessage";
+    private static final int TIMEOUT_MS = 500;
+
+    public static byte[] InetDiagReqV2(int protocol, InetSocketAddress local,
+                                       InetSocketAddress remote, int family, short flags) {
+        final byte[] bytes = new byte[StructNlMsgHdr.STRUCT_SIZE + StructInetDiagReqV2.STRUCT_SIZE];
+        final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
+        byteBuffer.order(ByteOrder.nativeOrder());
+
+        final StructNlMsgHdr nlMsgHdr = new StructNlMsgHdr();
+        nlMsgHdr.nlmsg_len = bytes.length;
+        nlMsgHdr.nlmsg_type = SOCK_DIAG_BY_FAMILY;
+        nlMsgHdr.nlmsg_flags = flags;
+        nlMsgHdr.pack(byteBuffer);
+
+        final StructInetDiagReqV2 inetDiagReqV2 = new StructInetDiagReqV2(protocol, local, remote,
+                family);
+        inetDiagReqV2.pack(byteBuffer);
+        return bytes;
+    }
+
+    public StructInetDiagMsg mStructInetDiagMsg;
+
+    private InetDiagMessage(StructNlMsgHdr header) {
+        super(header);
+        mStructInetDiagMsg = new StructInetDiagMsg();
+    }
+
+    public static InetDiagMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) {
+        final InetDiagMessage msg = new InetDiagMessage(header);
+        msg.mStructInetDiagMsg = StructInetDiagMsg.parse(byteBuffer);
+        return msg;
+    }
+
+    private static int lookupUidByFamily(int protocol, InetSocketAddress local,
+                                         InetSocketAddress remote, int family, short flags,
+                                         FileDescriptor fd)
+            throws ErrnoException, InterruptedIOException {
+        byte[] msg = InetDiagReqV2(protocol, local, remote, family, flags);
+        NetlinkSocket.sendMessage(fd, msg, 0, msg.length, TIMEOUT_MS);
+        ByteBuffer response = NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TIMEOUT_MS);
+
+        final NetlinkMessage nlMsg = NetlinkMessage.parse(response);
+        final StructNlMsgHdr hdr = nlMsg.getHeader();
+        if (hdr.nlmsg_type == NetlinkConstants.NLMSG_DONE) {
+            return INVALID_UID;
+        }
+        if (nlMsg instanceof InetDiagMessage) {
+            return ((InetDiagMessage) nlMsg).mStructInetDiagMsg.idiag_uid;
+        }
+        return INVALID_UID;
+    }
+
+    private static final int FAMILY[] = {AF_INET6, AF_INET};
+
+    private static int lookupUid(int protocol, InetSocketAddress local,
+                                 InetSocketAddress remote, FileDescriptor fd)
+            throws ErrnoException, InterruptedIOException {
+        int uid;
+
+        for (int family : FAMILY) {
+            /**
+             * For exact match lookup, swap local and remote for UDP lookups due to kernel
+             * bug which will not be fixed. See aosp/755889 and
+             * https://www.mail-archive.com/netdev@vger.kernel.org/msg248638.html
+             */
+            if (protocol == IPPROTO_UDP) {
+                uid = lookupUidByFamily(protocol, remote, local, family, NLM_F_REQUEST, fd);
+            } else {
+                uid = lookupUidByFamily(protocol, local, remote, family, NLM_F_REQUEST, fd);
+            }
+            if (uid != INVALID_UID) {
+                return uid;
+            }
+        }
+
+        /**
+         * For UDP it's possible for a socket to send packets to arbitrary destinations, even if the
+         * socket is not connected (and even if the socket is connected to a different destination).
+         * If we want this API to work for such packets, then on miss we need to do a second lookup
+         * with only the local address and port filled in.
+         * Always use flags == NLM_F_REQUEST | NLM_F_DUMP for wildcard.
+         */
+        if (protocol == IPPROTO_UDP) {
+            try {
+                InetSocketAddress wildcard = new InetSocketAddress(
+                        Inet6Address.getByName("::"), 0);
+                uid = lookupUidByFamily(protocol, local, wildcard, AF_INET6,
+                        (short) (NLM_F_REQUEST | NLM_F_DUMP), fd);
+                if (uid != INVALID_UID) {
+                    return uid;
+                }
+                wildcard = new InetSocketAddress(Inet4Address.getByName("0.0.0.0"), 0);
+                uid = lookupUidByFamily(protocol, local, wildcard, AF_INET,
+                        (short) (NLM_F_REQUEST | NLM_F_DUMP), fd);
+                if (uid != INVALID_UID) {
+                    return uid;
+                }
+            } catch (UnknownHostException e) {
+                Log.e(TAG, e.toString());
+            }
+        }
+        return INVALID_UID;
+    }
+
+    /**
+     * Use an inet_diag socket to look up the UID associated with the input local and remote
+     * address/port and protocol of a connection.
+     */
+    public static int getConnectionOwnerUid(int protocol, InetSocketAddress local,
+                                            InetSocketAddress remote) {
+        try {
+            final FileDescriptor fd = NetlinkSocket.forProto(NETLINK_INET_DIAG);
+            NetlinkSocket.connectToKernel(fd);
+
+            return lookupUid(protocol, local, remote, fd);
+
+        } catch (ErrnoException | SocketException | IllegalArgumentException
+                | InterruptedIOException e) {
+            Log.e(TAG, e.toString());
+        }
+        return INVALID_UID;
+    }
+
+    @Override
+    public String toString() {
+        return "InetDiagMessage{ "
+                + "nlmsghdr{" + (mHeader == null ? "" : mHeader.toString()) + "}, "
+                + "inet_diag_msg{"
+                + (mStructInetDiagMsg == null ? "" : mStructInetDiagMsg.toString()) + "} "
+                + "}";
+    }
+}
diff --git a/services/net/java/android/net/netlink/NetlinkConstants.java b/services/net/java/android/net/netlink/NetlinkConstants.java
index e331701..fc1551c 100644
--- a/services/net/java/android/net/netlink/NetlinkConstants.java
+++ b/services/net/java/android/net/netlink/NetlinkConstants.java
@@ -54,6 +54,12 @@
         return String.valueOf(family);
     }
 
+    public static String stringForProtocol(int protocol) {
+        if (protocol == OsConstants.IPPROTO_TCP) { return "IPPROTO_TCP"; }
+        if (protocol == OsConstants.IPPROTO_UDP) { return "IPPROTO_UDP"; }
+        return String.valueOf(protocol);
+    }
+
     public static String hexify(byte[] bytes) {
         if (bytes == null) { return "(null)"; }
         return HexDump.toHexString(bytes);
@@ -90,6 +96,9 @@
     public static final short RTM_GETRULE        = 34;
     public static final short RTM_NEWNDUSEROPT   = 68;
 
+    /* see &lt;linux_src&gt;/include/uapi/linux/sock_diag.h */
+    public static final short SOCK_DIAG_BY_FAMILY = 20;
+
     public static String stringForNlMsgType(short nlm_type) {
         switch (nlm_type) {
             case NLMSG_NOOP: return "NLMSG_NOOP";
diff --git a/services/net/java/android/net/netlink/NetlinkMessage.java b/services/net/java/android/net/netlink/NetlinkMessage.java
index 3bf75ca..a325db8 100644
--- a/services/net/java/android/net/netlink/NetlinkMessage.java
+++ b/services/net/java/android/net/netlink/NetlinkMessage.java
@@ -69,6 +69,8 @@
             case NetlinkConstants.RTM_DELNEIGH:
             case NetlinkConstants.RTM_GETNEIGH:
                 return (NetlinkMessage) RtNetlinkNeighborMessage.parse(nlmsghdr, byteBuffer);
+            case NetlinkConstants.SOCK_DIAG_BY_FAMILY:
+                return (NetlinkMessage) InetDiagMessage.parse(nlmsghdr, byteBuffer);
             default:
                 if (nlmsghdr.nlmsg_type <= NetlinkConstants.NLMSG_MAX_RESERVED) {
                     // Netlink control message.  Just parse the header for now,
diff --git a/services/net/java/android/net/netlink/StructInetDiagMsg.java b/services/net/java/android/net/netlink/StructInetDiagMsg.java
new file mode 100644
index 0000000..da824ad
--- /dev/null
+++ b/services/net/java/android/net/netlink/StructInetDiagMsg.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.netlink;
+
+import static java.nio.ByteOrder.BIG_ENDIAN;
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+
+import java.net.Inet4Address;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import android.util.Log;
+
+/**
+ * struct inet_diag_msg
+ *
+ * see &lt;linux_src&gt;/include/uapi/linux/inet_diag.h
+ *
+ * struct inet_diag_msg {
+ *      __u8    idiag_family;
+ *      __u8    idiag_state;
+ *      __u8    idiag_timer;
+ *      __u8    idiag_retrans;
+ *      struct  inet_diag_sockid id;
+ *      __u32   idiag_expires;
+ *      __u32   idiag_rqueue;
+ *      __u32   idiag_wqueue;
+ *      __u32   idiag_uid;
+ *      __u32   idiag_inode;
+ * };
+ *
+ * @hide
+ */
+public class StructInetDiagMsg {
+    public static final int STRUCT_SIZE = 4 + StructInetDiagSockId.STRUCT_SIZE + 20;
+    private static final int IDIAG_UID_OFFSET = StructNlMsgHdr.STRUCT_SIZE + 4 +
+            StructInetDiagSockId.STRUCT_SIZE + 12;
+    public int idiag_uid;
+
+    public static StructInetDiagMsg parse(ByteBuffer byteBuffer) {
+        StructInetDiagMsg struct = new StructInetDiagMsg();
+        struct.idiag_uid = byteBuffer.getInt(IDIAG_UID_OFFSET);
+        return struct;
+    }
+
+    @Override
+    public String toString() {
+        return "StructInetDiagMsg{ "
+                + "idiag_uid{" + idiag_uid + "}, "
+                + "}";
+    }
+}
diff --git a/services/net/java/android/net/netlink/StructInetDiagReqV2.java b/services/net/java/android/net/netlink/StructInetDiagReqV2.java
new file mode 100644
index 0000000..49a9325
--- /dev/null
+++ b/services/net/java/android/net/netlink/StructInetDiagReqV2.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.netlink;
+
+import static java.nio.ByteOrder.BIG_ENDIAN;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * struct inet_diag_req_v2
+ *
+ * see &lt;linux_src&gt;/include/uapi/linux/inet_diag.h
+ *
+ *      struct inet_diag_req_v2 {
+ *          __u8    sdiag_family;
+ *          __u8    sdiag_protocol;
+ *          __u8    idiag_ext;
+ *          __u8    pad;
+ *          __u32   idiag_states;
+ *          struct  inet_diag_sockid id;
+ *      };
+ *
+ * @hide
+ */
+public class StructInetDiagReqV2 {
+    public static final int STRUCT_SIZE = 8 + StructInetDiagSockId.STRUCT_SIZE;
+
+    private final byte sdiag_family;
+    private final byte sdiag_protocol;
+    private final StructInetDiagSockId id;
+    private final int INET_DIAG_REQ_V2_ALL_STATES = (int) 0xffffffff;
+
+
+    public StructInetDiagReqV2(int protocol, InetSocketAddress local, InetSocketAddress remote,
+                               int family) {
+        sdiag_family = (byte) family;
+        sdiag_protocol = (byte) protocol;
+        id = new StructInetDiagSockId(local, remote);
+    }
+
+    public void pack(ByteBuffer byteBuffer) {
+        // The ByteOrder must have already been set by the caller.
+        byteBuffer.put((byte) sdiag_family);
+        byteBuffer.put((byte) sdiag_protocol);
+        byteBuffer.put((byte) 0);
+        byteBuffer.put((byte) 0);
+        byteBuffer.putInt(INET_DIAG_REQ_V2_ALL_STATES);
+        id.pack(byteBuffer);
+    }
+
+    @Override
+    public String toString() {
+        final String familyStr = NetlinkConstants.stringForAddressFamily(sdiag_family);
+        final String protocolStr = NetlinkConstants.stringForAddressFamily(sdiag_protocol);
+
+        return "StructInetDiagReqV2{ "
+                + "sdiag_family{" + familyStr + "}, "
+                + "sdiag_protocol{" + protocolStr + "}, "
+                + "idiag_ext{" + 0 + ")}, "
+                + "pad{" + 0 + "}, "
+                + "idiag_states{" + Integer.toHexString(INET_DIAG_REQ_V2_ALL_STATES) + "}, "
+                + id.toString()
+                + "}";
+    }
+}
diff --git a/services/net/java/android/net/netlink/StructInetDiagSockId.java b/services/net/java/android/net/netlink/StructInetDiagSockId.java
new file mode 100644
index 0000000..2e9fa25
--- /dev/null
+++ b/services/net/java/android/net/netlink/StructInetDiagSockId.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.netlink;
+
+import static java.nio.ByteOrder.BIG_ENDIAN;
+
+import java.net.Inet4Address;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * struct inet_diag_req_v2
+ *
+ * see &lt;linux_src&gt;/include/uapi/linux/inet_diag.h
+ *
+ * struct inet_diag_sockid {
+ *        __be16    idiag_sport;
+ *        __be16    idiag_dport;
+ *        __be32    idiag_src[4];
+ *        __be32    idiag_dst[4];
+ *        __u32     idiag_if;
+ *        __u32     idiag_cookie[2];
+ * #define INET_DIAG_NOCOOKIE (~0U)
+ * };
+ *
+ * @hide
+ */
+public class StructInetDiagSockId {
+    public static final int STRUCT_SIZE = 48;
+
+    private final InetSocketAddress mLocSocketAddress;
+    private final InetSocketAddress mRemSocketAddress;
+    private final byte[] INET_DIAG_NOCOOKIE = new byte[]{
+            (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+            (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};
+    private final byte[] IPV4_PADDING = new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+    public StructInetDiagSockId(InetSocketAddress loc, InetSocketAddress rem) {
+        mLocSocketAddress = loc;
+        mRemSocketAddress = rem;
+    }
+
+    public void pack(ByteBuffer byteBuffer) {
+        byteBuffer.order(BIG_ENDIAN);
+        byteBuffer.putShort((short) mLocSocketAddress.getPort());
+        byteBuffer.putShort((short) mRemSocketAddress.getPort());
+        byteBuffer.put(mLocSocketAddress.getAddress().getAddress());
+        if (mLocSocketAddress.getAddress() instanceof Inet4Address) {
+            byteBuffer.put(IPV4_PADDING);
+        }
+        byteBuffer.put(mRemSocketAddress.getAddress().getAddress());
+        if (mRemSocketAddress.getAddress() instanceof Inet4Address) {
+            byteBuffer.put(IPV4_PADDING);
+        }
+        byteBuffer.order(ByteOrder.nativeOrder());
+        byteBuffer.putInt(0);
+        byteBuffer.put(INET_DIAG_NOCOOKIE);
+    }
+
+    @Override
+    public String toString() {
+        return "StructInetDiagSockId{ "
+                + "idiag_sport{" + mLocSocketAddress.getPort() + "}, "
+                + "idiag_dport{" + mRemSocketAddress.getPort() + "}, "
+                + "idiag_src{" + mLocSocketAddress.getAddress().getHostAddress() + "}, "
+                + "idiag_dst{" + mRemSocketAddress.getAddress().getHostAddress() + "}, "
+                + "idiag_if{" + 0 + "} "
+                + "idiag_cookie{INET_DIAG_NOCOOKIE}"
+                + "}";
+    }
+}
diff --git a/services/net/java/android/net/util/SharedLog.java b/services/net/java/android/net/util/SharedLog.java
index f7bf393..5a73a4e 100644
--- a/services/net/java/android/net/util/SharedLog.java
+++ b/services/net/java/android/net/util/SharedLog.java
@@ -17,6 +17,7 @@
 package android.net.util;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.text.TextUtils;
 import android.util.LocalLog;
 import android.util.Log;
@@ -92,10 +93,17 @@
     }
 
     /**
-     * Log an error due to an exception, with the exception stacktrace.
+     * Log an error due to an exception, with the exception stacktrace if provided.
+     *
+     * <p>The error and exception message appear in the shared log, but the stacktrace is only
+     * logged in general log output (logcat).
      */
-    public void e(@NonNull String msg, @NonNull Throwable e) {
-        Log.e(mTag, record(Category.ERROR, msg + ": " + e.getMessage()), e);
+    public void e(@NonNull String msg, @Nullable Throwable exception) {
+        if (exception == null) {
+            e(msg);
+            return;
+        }
+        Log.e(mTag, record(Category.ERROR, msg + ": " + exception.getMessage()), exception);
     }
 
     public void i(String msg) {
diff --git a/services/robotests/Android.mk b/services/robotests/Android.mk
index 8b59771..78c0be4 100644
--- a/services/robotests/Android.mk
+++ b/services/robotests/Android.mk
@@ -61,6 +61,7 @@
     $(call all-Iaidl-files-under, $(INTERNAL_BACKUP)) \
     $(call all-java-files-under, ../../core/java/android/app/backup) \
     $(call all-Iaidl-files-under, ../../core/java/android/app/backup) \
+    $(call all-java-files-under, ../../core/java/android/util/proto) \
     ../../core/java/android/content/pm/PackageInfo.java \
     ../../core/java/android/app/IBackupAgent.aidl \
     ../../core/java/android/util/KeyValueSettingObserver.java \
diff --git a/services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java b/services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java
index 57ebbfc..de915ab 100644
--- a/services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java
+++ b/services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java
@@ -122,6 +122,13 @@
         ShadowAppBackupUtils.reset();
     }
 
+    @Test
+    public void testMoreDebug_isFalse() throws Exception {
+        boolean moreDebug = BackupManagerService.MORE_DEBUG;
+
+        assertThat(moreDebug).isFalse();
+    }
+
     /* Tests for destination string */
 
     @Test
diff --git a/services/robotests/src/com/android/server/backup/encryption/chunk/ChunkListingTest.java b/services/robotests/src/com/android/server/backup/encryption/chunk/ChunkListingTest.java
new file mode 100644
index 0000000..383bf1d
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/encryption/chunk/ChunkListingTest.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup.encryption.chunk;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.platform.test.annotations.Presubmit;
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoOutputStream;
+import com.android.internal.util.Preconditions;
+import com.android.server.testing.FrameworkRobolectricTestRunner;
+import com.android.server.testing.SystemLoaderPackages;
+import com.google.common.base.Charsets;
+import java.io.ByteArrayInputStream;
+import java.util.Arrays;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+@RunWith(FrameworkRobolectricTestRunner.class)
+@Config(manifest = Config.NONE, sdk = 26)
+// Include android.util.proto in addition to classes under test because the latest versions of
+// android.util.proto.Proto{Input|Output}Stream are not part of Robolectric.
+@SystemLoaderPackages({"com.android.server.backup", "android.util.proto"})
+@Presubmit
+public class ChunkListingTest {
+    private static final String CHUNK_A = "CHUNK_A";
+    private static final String CHUNK_B = "CHUNK_B";
+    private static final String CHUNK_C = "CHUNK_C";
+
+    private static final int CHUNK_A_LENGTH = 256;
+    private static final int CHUNK_B_LENGTH = 1024;
+    private static final int CHUNK_C_LENGTH = 4055;
+
+    private ChunkHash mChunkHashA;
+    private ChunkHash mChunkHashB;
+    private ChunkHash mChunkHashC;
+
+    @Before
+    public void setUp() throws Exception {
+        mChunkHashA = getHash(CHUNK_A);
+        mChunkHashB = getHash(CHUNK_B);
+        mChunkHashC = getHash(CHUNK_C);
+    }
+
+    @Test
+    public void testHasChunk_whenChunkInListing_returnsTrue() throws Exception {
+        byte[] chunkListingProto =
+                createChunkListingProto(
+                        new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC},
+                        new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH});
+        ChunkListing chunkListing =
+                ChunkListing.readFromProto(
+                        new ProtoInputStream(new ByteArrayInputStream(chunkListingProto)));
+
+        boolean chunkAInList = chunkListing.hasChunk(mChunkHashA);
+        boolean chunkBInList = chunkListing.hasChunk(mChunkHashB);
+        boolean chunkCInList = chunkListing.hasChunk(mChunkHashC);
+
+        assertThat(chunkAInList).isTrue();
+        assertThat(chunkBInList).isTrue();
+        assertThat(chunkCInList).isTrue();
+    }
+
+    @Test
+    public void testHasChunk_whenChunkNotInListing_returnsFalse() throws Exception {
+        byte[] chunkListingProto =
+                createChunkListingProto(
+                        new ChunkHash[] {mChunkHashA, mChunkHashB},
+                        new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH});
+        ChunkListing chunkListing =
+                ChunkListing.readFromProto(
+                        new ProtoInputStream(new ByteArrayInputStream(chunkListingProto)));
+        ChunkHash chunkHashEmpty = getHash("");
+
+        boolean chunkCInList = chunkListing.hasChunk(mChunkHashC);
+        boolean emptyChunkInList = chunkListing.hasChunk(chunkHashEmpty);
+
+        assertThat(chunkCInList).isFalse();
+        assertThat(emptyChunkInList).isFalse();
+    }
+
+    @Test
+    public void testGetChunkEntry_returnsEntryWithCorrectLength() throws Exception {
+        byte[] chunkListingProto =
+                createChunkListingProto(
+                        new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC},
+                        new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH});
+        ChunkListing chunkListing =
+                ChunkListing.readFromProto(
+                        new ProtoInputStream(new ByteArrayInputStream(chunkListingProto)));
+
+        ChunkListing.Entry entryA = chunkListing.getChunkEntry(mChunkHashA);
+        ChunkListing.Entry entryB = chunkListing.getChunkEntry(mChunkHashB);
+        ChunkListing.Entry entryC = chunkListing.getChunkEntry(mChunkHashC);
+
+        assertThat(entryA.getLength()).isEqualTo(CHUNK_A_LENGTH);
+        assertThat(entryB.getLength()).isEqualTo(CHUNK_B_LENGTH);
+        assertThat(entryC.getLength()).isEqualTo(CHUNK_C_LENGTH);
+    }
+
+    @Test
+    public void testGetChunkEntry_returnsEntryWithCorrectStart() throws Exception {
+        byte[] chunkListingProto =
+                createChunkListingProto(
+                        new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC},
+                        new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH});
+        ChunkListing chunkListing =
+                ChunkListing.readFromProto(
+                        new ProtoInputStream(new ByteArrayInputStream(chunkListingProto)));
+
+        ChunkListing.Entry entryA = chunkListing.getChunkEntry(mChunkHashA);
+        ChunkListing.Entry entryB = chunkListing.getChunkEntry(mChunkHashB);
+        ChunkListing.Entry entryC = chunkListing.getChunkEntry(mChunkHashC);
+
+        assertThat(entryA.getStart()).isEqualTo(0);
+        assertThat(entryB.getStart()).isEqualTo(CHUNK_A_LENGTH);
+        assertThat(entryC.getStart()).isEqualTo(CHUNK_A_LENGTH + CHUNK_B_LENGTH);
+    }
+
+    @Test
+    public void testGetChunkEntry_returnsNullForNonExistentChunk() throws Exception {
+        byte[] chunkListingProto =
+                createChunkListingProto(
+                        new ChunkHash[] {mChunkHashA, mChunkHashB},
+                        new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH});
+        ChunkListing chunkListing =
+                ChunkListing.readFromProto(
+                        new ProtoInputStream(new ByteArrayInputStream(chunkListingProto)));
+
+        ChunkListing.Entry chunkEntryNonexistentChunk = chunkListing.getChunkEntry(mChunkHashC);
+
+        assertThat(chunkEntryNonexistentChunk).isNull();
+    }
+
+    @Test
+    public void testReadFromProto_whenEmptyProto_returnsChunkListingWith0Chunks() throws Exception {
+        ProtoInputStream emptyProto = new ProtoInputStream(new ByteArrayInputStream(new byte[] {}));
+
+        ChunkListing chunkListing = ChunkListing.readFromProto(emptyProto);
+
+        assertThat(chunkListing.getChunkCount()).isEqualTo(0);
+    }
+
+    @Test
+    public void testReadFromProto_returnsChunkListingWithCorrectSize() throws Exception {
+        byte[] chunkListingProto =
+                createChunkListingProto(
+                        new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC},
+                        new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH});
+
+        ChunkListing chunkListing =
+                ChunkListing.readFromProto(
+                        new ProtoInputStream(new ByteArrayInputStream(chunkListingProto)));
+
+        assertThat(chunkListing.getChunkCount()).isEqualTo(3);
+    }
+
+    private byte[] createChunkListingProto(ChunkHash[] hashes, int[] lengths) {
+        Preconditions.checkArgument(hashes.length == lengths.length);
+        ProtoOutputStream outputStream = new ProtoOutputStream();
+
+        for (int i = 0; i < hashes.length; ++i) {
+            writeToProtoOutputStream(outputStream, hashes[i], lengths[i]);
+        }
+        outputStream.flush();
+
+        return outputStream.getBytes();
+    }
+
+    private void writeToProtoOutputStream(ProtoOutputStream out, ChunkHash chunkHash, int length) {
+        long token = out.start(ChunksMetadataProto.ChunkListing.CHUNKS);
+        out.write(ChunksMetadataProto.Chunk.HASH, chunkHash.getHash());
+        out.write(ChunksMetadataProto.Chunk.LENGTH, length);
+        out.end(token);
+    }
+
+    private ChunkHash getHash(String name) {
+        return new ChunkHash(
+                Arrays.copyOf(name.getBytes(Charsets.UTF_8), ChunkHash.HASH_LENGTH_BYTES));
+    }
+}
diff --git a/services/robotests/src/com/android/server/backup/encryption/chunk/ChunkTest.java b/services/robotests/src/com/android/server/backup/encryption/chunk/ChunkTest.java
new file mode 100644
index 0000000..1dd7dc8
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/encryption/chunk/ChunkTest.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup.encryption.chunk;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.platform.test.annotations.Presubmit;
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoOutputStream;
+import com.android.server.testing.FrameworkRobolectricTestRunner;
+import com.android.server.testing.SystemLoaderPackages;
+import com.google.common.base.Charsets;
+import java.io.ByteArrayInputStream;
+import java.util.Arrays;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+@RunWith(FrameworkRobolectricTestRunner.class)
+@Config(manifest = Config.NONE, sdk = 26)
+// Include android.util.proto in addition to classes under test because the latest versions of
+// android.util.proto.Proto{Input|Output}Stream are not part of Robolectric.
+@SystemLoaderPackages({"com.android.server.backup", "android.util.proto"})
+@Presubmit
+public class ChunkTest {
+    private static final String CHUNK_A = "CHUNK_A";
+    private static final int CHUNK_A_LENGTH = 256;
+
+    private ChunkHash mChunkHashA;
+
+    @Before
+    public void setUp() throws Exception {
+        mChunkHashA = getHash(CHUNK_A);
+    }
+
+    @Test
+    public void testReadFromProto_readsCorrectly() throws Exception {
+        ProtoOutputStream out = new ProtoOutputStream();
+        out.write(ChunksMetadataProto.Chunk.HASH, mChunkHashA.getHash());
+        out.write(ChunksMetadataProto.Chunk.LENGTH, CHUNK_A_LENGTH);
+        out.flush();
+        byte[] protoBytes = out.getBytes();
+
+        Chunk chunk =
+                Chunk.readFromProto(new ProtoInputStream(new ByteArrayInputStream(protoBytes)));
+
+        assertThat(chunk.getHash()).isEqualTo(mChunkHashA.getHash());
+        assertThat(chunk.getLength()).isEqualTo(CHUNK_A_LENGTH);
+    }
+
+    @Test
+    public void testReadFromProto_whenFieldsWrittenInReversedOrder_readsCorrectly()
+            throws Exception {
+        ProtoOutputStream out = new ProtoOutputStream();
+        // Write fields of Chunk proto in reverse order.
+        out.write(ChunksMetadataProto.Chunk.LENGTH, CHUNK_A_LENGTH);
+        out.write(ChunksMetadataProto.Chunk.HASH, mChunkHashA.getHash());
+        out.flush();
+        byte[] protoBytes = out.getBytes();
+
+        Chunk chunk =
+                Chunk.readFromProto(new ProtoInputStream(new ByteArrayInputStream(protoBytes)));
+
+        assertThat(chunk.getHash()).isEqualTo(mChunkHashA.getHash());
+        assertThat(chunk.getLength()).isEqualTo(CHUNK_A_LENGTH);
+    }
+
+    @Test
+    public void testReadFromProto_whenEmptyProto_returnsEmptyHash() throws Exception {
+        ProtoInputStream emptyProto = new ProtoInputStream(new ByteArrayInputStream(new byte[] {}));
+
+        Chunk chunk = Chunk.readFromProto(emptyProto);
+
+        assertThat(chunk.getHash()).asList().hasSize(0);
+        assertThat(chunk.getLength()).isEqualTo(0);
+    }
+
+    @Test
+    public void testReadFromProto_whenOnlyHashSet_returnsChunkWithOnlyHash() throws Exception {
+        ProtoOutputStream out = new ProtoOutputStream();
+        out.write(ChunksMetadataProto.Chunk.HASH, mChunkHashA.getHash());
+        out.flush();
+        byte[] protoBytes = out.getBytes();
+
+        Chunk chunk =
+                Chunk.readFromProto(new ProtoInputStream(new ByteArrayInputStream(protoBytes)));
+
+        assertThat(chunk.getHash()).isEqualTo(mChunkHashA.getHash());
+        assertThat(chunk.getLength()).isEqualTo(0);
+    }
+
+    @Test
+    public void testReadFromProto_whenOnlyLengthSet_returnsChunkWithOnlyLength() throws Exception {
+        ProtoOutputStream out = new ProtoOutputStream();
+        out.write(ChunksMetadataProto.Chunk.LENGTH, CHUNK_A_LENGTH);
+        out.flush();
+        byte[] protoBytes = out.getBytes();
+
+        Chunk chunk =
+                Chunk.readFromProto(new ProtoInputStream(new ByteArrayInputStream(protoBytes)));
+
+        assertThat(chunk.getHash()).isEqualTo(new byte[] {});
+        assertThat(chunk.getLength()).isEqualTo(CHUNK_A_LENGTH);
+    }
+
+    private ChunkHash getHash(String name) {
+        return new ChunkHash(
+                Arrays.copyOf(name.getBytes(Charsets.UTF_8), ChunkHash.HASH_LENGTH_BYTES));
+    }
+}
diff --git a/services/robotests/src/com/android/server/backup/encryption/chunk/EncryptedChunkOrderingTest.java b/services/robotests/src/com/android/server/backup/encryption/chunk/EncryptedChunkOrderingTest.java
new file mode 100644
index 0000000..1cd1528
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/encryption/chunk/EncryptedChunkOrderingTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup.encryption.chunk;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.platform.test.annotations.Presubmit;
+import com.android.server.testing.FrameworkRobolectricTestRunner;
+import com.android.server.testing.SystemLoaderPackages;
+import com.google.common.primitives.Bytes;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+@RunWith(FrameworkRobolectricTestRunner.class)
+@Config(manifest = Config.NONE, sdk = 26)
+@SystemLoaderPackages({"com.android.server.backup"})
+@Presubmit
+public class EncryptedChunkOrderingTest {
+    private static final byte[] TEST_BYTE_ARRAY_1 = new byte[] {1, 2, 3, 4, 5};
+    private static final byte[] TEST_BYTE_ARRAY_2 = new byte[] {5, 4, 3, 2, 1};
+
+    @Test
+    public void testEncryptedChunkOrdering_returnsValue() {
+        EncryptedChunkOrdering encryptedChunkOrdering =
+                EncryptedChunkOrdering.create(TEST_BYTE_ARRAY_1);
+
+        byte[] bytes = encryptedChunkOrdering.encryptedChunkOrdering();
+
+        assertThat(bytes)
+                .asList()
+                .containsExactlyElementsIn(Bytes.asList(TEST_BYTE_ARRAY_1))
+                .inOrder();
+    }
+
+    @Test
+    public void testEquals() {
+        EncryptedChunkOrdering chunkOrdering1 = EncryptedChunkOrdering.create(TEST_BYTE_ARRAY_1);
+        EncryptedChunkOrdering equalChunkOrdering1 =
+                EncryptedChunkOrdering.create(TEST_BYTE_ARRAY_1);
+        EncryptedChunkOrdering chunkOrdering2 = EncryptedChunkOrdering.create(TEST_BYTE_ARRAY_2);
+
+        assertThat(chunkOrdering1).isEqualTo(equalChunkOrdering1);
+        assertThat(chunkOrdering1).isNotEqualTo(chunkOrdering2);
+    }
+
+    @Test
+    public void testHashCode() {
+        EncryptedChunkOrdering chunkOrdering1 = EncryptedChunkOrdering.create(TEST_BYTE_ARRAY_1);
+        EncryptedChunkOrdering equalChunkOrdering1 =
+                EncryptedChunkOrdering.create(TEST_BYTE_ARRAY_1);
+        EncryptedChunkOrdering chunkOrdering2 = EncryptedChunkOrdering.create(TEST_BYTE_ARRAY_2);
+
+        int hash1 = chunkOrdering1.hashCode();
+        int equalHash1 = equalChunkOrdering1.hashCode();
+        int hash2 = chunkOrdering2.hashCode();
+
+        assertThat(hash1).isEqualTo(equalHash1);
+        assertThat(hash1).isNotEqualTo(hash2);
+    }
+}
diff --git a/services/robotests/src/com/android/server/backup/keyvalue/AgentExceptionTest.java b/services/robotests/src/com/android/server/backup/keyvalue/AgentExceptionTest.java
new file mode 100644
index 0000000..3730335
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/keyvalue/AgentExceptionTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup.keyvalue;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.platform.test.annotations.Presubmit;
+
+import com.android.server.testing.FrameworkRobolectricTestRunner;
+import com.android.server.testing.SystemLoaderPackages;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+import java.io.IOException;
+
+@RunWith(FrameworkRobolectricTestRunner.class)
+@Config(manifest = Config.NONE, sdk = 26)
+@SystemLoaderPackages({"com.android.server.backup"})
+@Presubmit
+public class AgentExceptionTest {
+    @Test
+    public void testTransitory_isTransitory() throws Exception {
+        AgentException exception = AgentException.transitory();
+
+        assertThat(exception.isTransitory()).isTrue();
+    }
+
+    @Test
+    public void testTransitory_withCause() throws Exception {
+        Exception cause = new IOException();
+
+        AgentException exception = AgentException.transitory(cause);
+
+        assertThat(exception.isTransitory()).isTrue();
+        assertThat(exception.getCause()).isEqualTo(cause);
+    }
+
+    @Test
+    public void testPermanent_isNotTransitory() throws Exception {
+        AgentException exception = AgentException.permanent();
+
+        assertThat(exception.isTransitory()).isFalse();
+    }
+
+    @Test
+    public void testPermanent_withCause() throws Exception {
+        Exception cause = new IOException();
+
+        AgentException exception = AgentException.permanent(cause);
+
+        assertThat(exception.isTransitory()).isFalse();
+        assertThat(exception.getCause()).isEqualTo(cause);
+    }
+}
diff --git a/services/robotests/src/com/android/server/backup/keyvalue/BackupExceptionTest.java b/services/robotests/src/com/android/server/backup/keyvalue/BackupExceptionTest.java
new file mode 100644
index 0000000..5ea74f1
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/keyvalue/BackupExceptionTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup.keyvalue;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.platform.test.annotations.Presubmit;
+
+import com.android.server.testing.FrameworkRobolectricTestRunner;
+import com.android.server.testing.SystemLoaderPackages;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+import java.io.IOException;
+
+@RunWith(FrameworkRobolectricTestRunner.class)
+@Config(manifest = Config.NONE, sdk = 26)
+@SystemLoaderPackages({"com.android.server.backup"})
+@Presubmit
+public class BackupExceptionTest {
+    @Test
+    public void testConstructor_passesCause() {
+        Exception cause = new IOException();
+
+        Exception exception = new BackupException(cause);
+
+        assertThat(exception.getCause()).isEqualTo(cause);
+    }
+}
diff --git a/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupReporterTest.java b/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupReporterTest.java
index 21b90f1..31e8333 100644
--- a/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupReporterTest.java
+++ b/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupReporterTest.java
@@ -62,6 +62,13 @@
     }
 
     @Test
+    public void testMoreDebug_isFalse() throws Exception {
+        boolean moreDebug = KeyValueBackupReporter.MORE_DEBUG;
+
+        assertThat(moreDebug).isFalse();
+    }
+
+    @Test
     public void testOnNewThread_logsCorrectly() throws Exception {
         KeyValueBackupReporter.onNewThread("foo");
 
@@ -81,39 +88,4 @@
 
         assertThat(observer).isEqualTo(mObserver);
     }
-
-    @Test
-    public void testOnRevertTask_logsCorrectly() throws Exception {
-        setMoreDebug(true);
-
-        mReporter.onRevertTask();
-
-        assertLogcat(TAG, Log.INFO);
-    }
-
-    @Test
-    public void testOnRemoteCallReturned_logsCorrectly() throws Exception {
-        setMoreDebug(true);
-
-        mReporter.onRemoteCallReturned(RemoteResult.of(3), "onFoo()");
-
-        assertLogcat(TAG, Log.VERBOSE);
-        ShadowLog.LogItem log = ShadowLog.getLogsForTag(TAG).get(0);
-        assertThat(log.msg).contains("onFoo()");
-        assertThat(log.msg).contains("3");
-    }
-
-    /**
-     * HACK: We actually want {@link KeyValueBackupReporter#MORE_DEBUG} to be a constant to be able
-     * to strip those lines at build time. So, we have to do this to test :(
-     */
-    private static void setMoreDebug(boolean value)
-            throws NoSuchFieldException, IllegalAccessException {
-        if (KeyValueBackupReporter.MORE_DEBUG == value) {
-            return;
-        }
-        Field moreDebugField = KeyValueBackupReporter.class.getDeclaredField("MORE_DEBUG");
-        moreDebugField.setAccessible(true);
-        moreDebugField.set(null, value);
-    }
 }
diff --git a/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
index b4bc9d1..fb57d68 100644
--- a/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
+++ b/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
@@ -155,9 +155,7 @@
 import java.util.concurrent.TimeoutException;
 import java.util.stream.Stream;
 
-// TODO: When returning to RUNNING_QUEUE vs FINAL, RUNNING_QUEUE sets status = OK. Why? Verify?
-// TODO: Check queue in general, behavior w/ multiple packages
-// TODO: Test PM invocation
+// TODO: Test agents timing out
 @RunWith(FrameworkRobolectricTestRunner.class)
 @Config(
         manifest = Config.NONE,
@@ -370,6 +368,47 @@
     }
 
     @Test
+    public void testRunTask_whenOnePackage_cleansUpPmFiles() throws Exception {
+        TransportMock transportMock = setUpInitializedTransport(mTransport);
+        setUpAgent(PACKAGE_1);
+        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+
+        runTask(task);
+
+        assertCleansUpFiles(mTransport, PM_PACKAGE);
+    }
+
+    @Test
+    public void testRunTask_whenTransportReturnsTransportErrorForPm_cleansUpPmFiles()
+            throws Exception {
+        TransportMock transportMock = setUpInitializedTransport(mTransport);
+        when(transportMock.transport.performBackup(
+                        argThat(packageInfo(PM_PACKAGE)), any(), anyInt()))
+                .thenReturn(BackupTransport.TRANSPORT_PACKAGE_REJECTED);
+        setUpAgent(PACKAGE_1);
+        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+
+        runTask(task);
+
+        assertCleansUpFiles(mTransport, PM_PACKAGE);
+    }
+
+    @Test
+    public void testRunTask_whenTransportReturnsTransportErrorForPm_resetsBackupState()
+            throws Exception {
+        TransportMock transportMock = setUpInitializedTransport(mTransport);
+        when(transportMock.transport.performBackup(
+                        argThat(packageInfo(PM_PACKAGE)), any(), anyInt()))
+                .thenReturn(BackupTransport.TRANSPORT_PACKAGE_REJECTED);
+        setUpAgent(PACKAGE_1);
+        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+
+        runTask(task);
+
+        verify(mBackupManagerService).resetBackupState(getStateDirectory(mTransport).toFile());
+    }
+
+    @Test
     public void testRunTask_whenOnePackage_updatesBookkeeping() throws Exception {
         // Transport has to be initialized to not reset current token
         TransportMock transportMock = setUpInitializedTransport(mTransport);
@@ -418,7 +457,7 @@
     public void testRunTask_whenNonPmPackageAndNonIncremental_doesNotBackUpPm() throws Exception {
         TransportMock transportMock = setUpInitializedTransport(mTransport);
         setUpAgentWithData(PACKAGE_1);
-        PackageManagerBackupAgent pmAgent = spy(createPmAgent());
+        BackupAgent pmAgent = spy(createPmAgent());
         when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent));
         KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true, PACKAGE_1);
 
@@ -431,7 +470,7 @@
     public void testRunTask_whenNonPmPackageAndPmAndNonIncremental_backsUpPm() throws Exception {
         TransportMock transportMock = setUpInitializedTransport(mTransport);
         setUpAgentWithData(PACKAGE_1);
-        PackageManagerBackupAgent pmAgent = spy(createPmAgent());
+        BackupAgent pmAgent = spy(createPmAgent());
         when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent));
         KeyValueBackupTask task =
                 createKeyValueBackupTask(transportMock, true, PACKAGE_1, PM_PACKAGE);
@@ -445,7 +484,7 @@
     public void testRunTask_whenNonPmPackageAndIncremental_backsUpPm() throws Exception {
         TransportMock transportMock = setUpInitializedTransport(mTransport);
         setUpAgentWithData(PACKAGE_1);
-        PackageManagerBackupAgent pmAgent = spy(createPmAgent());
+        BackupAgent pmAgent = spy(createPmAgent());
         when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent));
         KeyValueBackupTask task = createKeyValueBackupTask(transportMock, false, PACKAGE_1);
 
@@ -529,6 +568,35 @@
     }
 
     @Test
+    public void testRunTask_whenPackageUnknown() throws Exception {
+        TransportMock transportMock = setUpInitializedTransport(mTransport);
+        // Not calling setUpAgent() for PACKAGE_1
+        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+
+        runTask(task);
+
+        verify(transportMock.transport, never())
+                .performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt());
+        verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_PACKAGE_NOT_FOUND);
+        verify(mObserver).backupFinished(SUCCESS);
+        assertBackupNotPendingFor(PACKAGE_1);
+    }
+
+    @Test
+    public void testRunTask_whenFirstPackageUnknown_callsTransportForSecondPackage()
+            throws Exception {
+        TransportMock transportMock = setUpInitializedTransport(mTransport);
+        // Not calling setUpAgent() for PACKAGE_1
+        setUpAgentWithData(PACKAGE_2);
+        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2);
+
+        runTask(task);
+
+        verify(transportMock.transport)
+                .performBackup(argThat(packageInfo(PACKAGE_2)), any(), anyInt());
+    }
+
+    @Test
     public void testRunTask_whenPackageNotEligibleForBackup() throws Exception {
         TransportMock transportMock = setUpInitializedTransport(mTransport);
         AgentMock agentMock = setUpAgentWithData(PACKAGE_1.backupNotAllowed());
@@ -545,6 +613,19 @@
     }
 
     @Test
+    public void testRunTask_whenFirstPackageNotEligibleForBackup_callsTransportForSecondPackage()
+            throws Exception {
+        TransportMock transportMock = setUpInitializedTransport(mTransport);
+        setUpAgentsWithData(PACKAGE_1.backupNotAllowed(), PACKAGE_2);
+        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2);
+
+        runTask(task);
+
+        verify(transportMock.transport)
+                .performBackup(argThat(packageInfo(PACKAGE_2)), any(), anyInt());
+    }
+
+    @Test
     public void testRunTask_whenPackageDoesFullBackup() throws Exception {
         TransportMock transportMock = setUpInitializedTransport(mTransport);
         PackageData packageData = fullBackupPackage(1);
@@ -561,6 +642,20 @@
     }
 
     @Test
+    public void testRunTask_whenFirstPackageDoesFullBackup_callsTransportForSecondPackage()
+            throws Exception {
+        TransportMock transportMock = setUpInitializedTransport(mTransport);
+        PackageData packageData = fullBackupPackage(1);
+        setUpAgentsWithData(packageData, PACKAGE_2);
+        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, packageData, PACKAGE_2);
+
+        runTask(task);
+
+        verify(transportMock.transport)
+                .performBackup(argThat(packageInfo(PACKAGE_2)), any(), anyInt());
+    }
+
+    @Test
     public void testRunTask_whenPackageIsStopped() throws Exception {
         TransportMock transportMock = setUpInitializedTransport(mTransport);
         AgentMock agentMock = setUpAgentWithData(PACKAGE_1.stopped());
@@ -575,18 +670,16 @@
     }
 
     @Test
-    public void testRunTask_whenPackageUnknown() throws Exception {
+    public void testRunTask_whenFirstPackageIsStopped_callsTransportForSecondPackage()
+            throws Exception {
         TransportMock transportMock = setUpInitializedTransport(mTransport);
-        // Not calling setUpAgent()
-        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+        setUpAgentsWithData(PACKAGE_1.stopped(), PACKAGE_2);
+        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2);
 
         runTask(task);
 
-        verify(transportMock.transport, never())
-                .performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt());
-        verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_PACKAGE_NOT_FOUND);
-        verify(mObserver).backupFinished(SUCCESS);
-        assertBackupNotPendingFor(PACKAGE_1);
+        verify(transportMock.transport)
+                .performBackup(argThat(packageInfo(PACKAGE_2)), any(), anyInt());
     }
 
     @Test
@@ -629,6 +722,7 @@
         verify(mBackupManagerService).setWorkSource(null);
         verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_AGENT_FAILURE);
         verify(mObserver).backupFinished(BackupManager.SUCCESS);
+        assertBackupPendingFor(PACKAGE_1);
     }
 
     @Test
@@ -645,6 +739,7 @@
         verify(mBackupManagerService).setWorkSource(null);
         verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_AGENT_FAILURE);
         verify(mObserver).backupFinished(BackupManager.SUCCESS);
+        assertBackupPendingFor(PACKAGE_1);
     }
 
     @Test
@@ -798,7 +893,7 @@
 
         runTask(task);
 
-        assertBackupNotPendingFor(PACKAGE_1);
+        assertBackupPendingFor(PACKAGE_1);
     }
 
     @Test
@@ -1140,6 +1235,38 @@
     }
 
     @Test
+    public void testRunTask_whenPmAgentWritesData_callsTransportPerformBackupWithAgentData()
+            throws Exception {
+        TransportMock transportMock = setUpInitializedTransport(mTransport);
+        setUpAgent(PACKAGE_1);
+        Path backupDataPath = createTemporaryFile();
+        when(transportMock.transport.performBackup(
+                        argThat(packageInfo(PM_PACKAGE)), any(), anyInt()))
+                .then(copyBackupDataTo(backupDataPath));
+        BackupAgent pmAgent = spy(createPmAgent());
+        when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent));
+        agentOnBackupDo(
+                pmAgent,
+                (oldState, dataOutput, newState) -> {
+                    writeData(dataOutput, "key1", "data1".getBytes());
+                    writeData(dataOutput, "key2", "data2".getBytes());
+                    writeState(newState, "newState".getBytes());
+                });
+        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+
+        runTask(task);
+
+        verify(transportMock.transport)
+                .performBackup(argThat(packageInfo(PM_PACKAGE)), any(), anyInt());
+        try (FileInputStream inputStream = new FileInputStream(backupDataPath.toFile())) {
+            BackupDataInput backupData = new BackupDataInput(inputStream.getFD());
+            assertDataHasKeyValue(backupData, "key1", "data1".getBytes());
+            assertDataHasKeyValue(backupData, "key2", "data2".getBytes());
+            assertThat(backupData.readNextHeader()).isFalse();
+        }
+    }
+
+    @Test
     public void testRunTask_whenPerformBackupSucceeds_callsTransportFinishBackup()
             throws Exception {
         TransportMock transportMock = setUpInitializedTransport(mTransport);
@@ -1176,6 +1303,50 @@
     }
 
     @Test
+    public void testRunTask_whenFinishBackupSucceedsForPm_cleansUp() throws Exception {
+        TransportMock transportMock = setUpInitializedTransport(mTransport);
+        setUpAgent(PACKAGE_1);
+        when(transportMock.transport.finishBackup()).thenReturn(BackupTransport.TRANSPORT_OK);
+        BackupAgent pmAgent = spy(createPmAgent());
+        when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent));
+        agentOnBackupDo(
+                pmAgent,
+                (oldState, dataOutput, newState) -> {
+                    writeData(dataOutput, "key", "data".getBytes());
+                    writeState(newState, "newState".getBytes());
+                });
+        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+
+        runTask(task);
+
+        assertThat(Files.readAllBytes(getStateFile(mTransport, PM_PACKAGE)))
+                .isEqualTo("newState".getBytes());
+        assertCleansUpFiles(mTransport, PM_PACKAGE);
+        // We don't unbind PM
+        verify(mBackupManagerService, never()).unbindAgent(argThat(applicationInfo(PM_PACKAGE)));
+    }
+
+    @Test
+    public void testRunTask_whenFinishBackupSucceedsForPm_doesNotUnbindPm() throws Exception {
+        TransportMock transportMock = setUpInitializedTransport(mTransport);
+        setUpAgent(PACKAGE_1);
+        when(transportMock.transport.finishBackup()).thenReturn(BackupTransport.TRANSPORT_OK);
+        BackupAgent pmAgent = spy(createPmAgent());
+        when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent));
+        agentOnBackupDo(
+                pmAgent,
+                (oldState, dataOutput, newState) -> {
+                    writeData(dataOutput, "key", "data".getBytes());
+                    writeState(newState, "newState".getBytes());
+                });
+        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+
+        runTask(task);
+
+        verify(mBackupManagerService, never()).unbindAgent(argThat(applicationInfo(PM_PACKAGE)));
+    }
+
+    @Test
     public void testRunTask_whenFinishBackupSucceeds_logsBackupPackageEvent() throws Exception {
         TransportMock transportMock = setUpInitializedTransport(mTransport);
         setUpAgentWithData(PACKAGE_1);
@@ -1354,6 +1525,7 @@
     public void testRunTask_whenTransportReturnsQuotaExceeded_updatesBookkeeping()
             throws Exception {
         TransportMock transportMock = setUpInitializedTransport(mTransport);
+        setUpAgentWithData(PACKAGE_1);
         when(transportMock.transport.performBackup(
                         argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                 .thenReturn(BackupTransport.TRANSPORT_QUOTA_EXCEEDED);
@@ -1701,9 +1873,9 @@
     }
 
     @Test
-    public void testRunTask_whenPmAgentFails() throws Exception {
+    public void testRunTask_whenPmAgentFails_reportsCorrectly() throws Exception {
         TransportMock transportMock = setUpInitializedTransport(mTransport);
-        PackageManagerBackupAgent pmAgent = createThrowingPmAgent(new RuntimeException());
+        BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException());
         when(mBackupManagerService.makeMetadataAgent()).thenReturn(pmAgent);
         KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
 
@@ -1718,6 +1890,75 @@
     }
 
     @Test
+    public void testRunTask_whenPmAgentFails_revertsTask() throws Exception {
+        TransportMock transportMock = setUpInitializedTransport(mTransport);
+        setUpAgent(PACKAGE_1);
+        BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException());
+        when(mBackupManagerService.makeMetadataAgent()).thenReturn(pmAgent);
+        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+
+        runTask(task);
+
+        assertTaskReverted(transportMock, PACKAGE_1);
+    }
+
+    @Test
+    public void testRunTask_whenPmAgentFails_cleansUpFiles() throws Exception {
+        TransportMock transportMock = setUpInitializedTransport(mTransport);
+        setUpAgent(PACKAGE_1);
+        BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException());
+        when(mBackupManagerService.makeMetadataAgent()).thenReturn(pmAgent);
+        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+
+        runTask(task);
+
+        assertCleansUpFiles(mTransport, PM_PACKAGE);
+    }
+
+    @Test
+    public void testRunTask_whenPmAgentFails_resetsBackupState() throws Exception {
+        TransportMock transportMock = setUpInitializedTransport(mTransport);
+        setUpAgent(PACKAGE_1);
+        BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException());
+        when(mBackupManagerService.makeMetadataAgent()).thenReturn(pmAgent);
+        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+
+        runTask(task);
+
+        verify(mBackupManagerService).resetBackupState(getStateDirectory(mTransport).toFile());
+    }
+
+    @Test
+    public void testRunTask_whenMarkCancelDuringPmOnBackup_resetsBackupState() throws Exception {
+        TransportMock transportMock = setUpInitializedTransport(mTransport);
+        setUpAgent(PACKAGE_1);
+        BackupAgent pmAgent = spy(createPmAgent());
+        when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent));
+        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+        agentOnBackupDo(
+                pmAgent, (oldState, dataOutput, newState) -> runInWorkerThread(task::markCancel));
+
+        runTask(task);
+
+        verify(mBackupManagerService).resetBackupState(getStateDirectory(mTransport).toFile());
+    }
+
+    @Test
+    public void testRunTask_whenMarkCancelDuringPmOnBackup_cleansUpFiles() throws Exception {
+        TransportMock transportMock = setUpInitializedTransport(mTransport);
+        setUpAgent(PACKAGE_1);
+        BackupAgent pmAgent = spy(createPmAgent());
+        when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent));
+        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+        agentOnBackupDo(
+                pmAgent, (oldState, dataOutput, newState) -> runInWorkerThread(task::markCancel));
+
+        runTask(task);
+
+        assertCleansUpFiles(mTransport, PM_PACKAGE);
+    }
+
+    @Test
     public void testRunTask_whenBackupRunning_doesNotThrow() throws Exception {
         TransportMock transportMock = setUpInitializedTransport(mTransport);
         when(mBackupManagerService.isBackupOperationInProgress()).thenReturn(true);
@@ -1736,7 +1977,7 @@
 
         runTask(task);
 
-        verify(mReporter).onReadAgentDataError(eq(PACKAGE_1.packageName), any());
+        verify(mReporter).onAgentDataError(eq(PACKAGE_1.packageName), any());
     }
 
     @Test
@@ -1779,6 +2020,24 @@
     }
 
     @Test
+    public void testRunTask_whenMarkCancelDuringAgentOnBackup_cleansUpFiles() throws Exception {
+        TransportMock transportMock = setUpInitializedTransport(mTransport);
+        AgentMock agentMock = setUpAgent(PACKAGE_1);
+        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+        agentOnBackupDo(
+                agentMock,
+                (oldState, dataOutput, newState) -> {
+                    writeData(dataOutput, "key", "data".getBytes());
+                    writeState(newState, "newState".getBytes());
+                    runInWorkerThread(task::markCancel);
+                });
+
+        runTask(task);
+
+        assertCleansUpFiles(mTransport, PACKAGE_1);
+    }
+
+    @Test
     public void
             testRunTask_whenMarkCancelDuringFirstAgentOnBackup_doesNotCallTransportAfterWaitCancel()
                     throws Exception {
@@ -2293,20 +2552,28 @@
      */
     private static void agentOnBackupDo(AgentMock agentMock, BackupAgentOnBackup function)
             throws Exception {
-        doAnswer(
-                        (BackupAgentOnBackup)
-                                (oldState, dataOutput, newState) -> {
-                                    ByteArrayOutputStream outputStream =
-                                            new ByteArrayOutputStream();
-                                    transferStreamedData(
-                                            new FileInputStream(oldState.getFileDescriptor()),
-                                            outputStream);
-                                    agentMock.oldState = outputStream.toByteArray();
-                                    agentMock.oldStateHistory.add(agentMock.oldState);
-                                    function.onBackup(oldState, dataOutput, newState);
-                                })
-                .when(agentMock.agent)
-                .onBackup(any(), any(), any());
+        agentOnBackupDo(
+                agentMock.agent,
+                (oldState, dataOutput, newState) -> {
+                    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+                    transferStreamedData(
+                            new FileInputStream(oldState.getFileDescriptor()), outputStream);
+                    agentMock.oldState = outputStream.toByteArray();
+                    agentMock.oldStateHistory.add(agentMock.oldState);
+                    function.onBackup(oldState, dataOutput, newState);
+                });
+    }
+
+    /**
+     * Implements {@code function} for {@link BackupAgent#onBackup(ParcelFileDescriptor,
+     * BackupDataOutput, ParcelFileDescriptor)} of {@code agentMock}.
+     *
+     * @see #agentOnBackupDo(AgentMock, BackupAgentOnBackup)
+     * @see #remoteAgentOnBackupThrows(AgentMock, BackupAgentOnBackup)
+     */
+    private static void agentOnBackupDo(BackupAgent backupAgent, BackupAgentOnBackup function)
+            throws IOException {
+        doAnswer(function).when(backupAgent).onBackup(any(), any(), any());
     }
 
     /**
@@ -2400,6 +2667,10 @@
             // constructor
             assertJournalDoesNotContain(mBackupManagerService.getJournal(), packageName);
             assertThat(mBackupManagerService.getPendingBackups()).doesNotContainKey(packageName);
+            // Also verifying BMS is never called since for some cases the package wouldn't be
+            // pending for other reasons (for example it's not eligible for backup). Regardless of
+            // these reasons, we shouldn't mark them as pending backup (call dataChangedImpl()).
+            verify(mBackupManagerService, never()).dataChangedImpl(packageName);
         }
     }
 
diff --git a/services/robotests/src/com/android/server/backup/keyvalue/TaskExceptionTest.java b/services/robotests/src/com/android/server/backup/keyvalue/TaskExceptionTest.java
new file mode 100644
index 0000000..4b79657
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/keyvalue/TaskExceptionTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup.keyvalue;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.expectThrows;
+
+import android.app.backup.BackupTransport;
+import android.platform.test.annotations.Presubmit;
+
+import com.android.server.testing.FrameworkRobolectricTestRunner;
+import com.android.server.testing.SystemLoaderPackages;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+import java.io.IOException;
+
+@RunWith(FrameworkRobolectricTestRunner.class)
+@Config(manifest = Config.NONE, sdk = 26)
+@SystemLoaderPackages({"com.android.server.backup"})
+@Presubmit
+public class TaskExceptionTest {
+    @Test
+    public void testStateCompromised() {
+        TaskException exception = TaskException.stateCompromised();
+
+        assertThat(exception.isStateCompromised()).isTrue();
+        assertThat(exception.getStatus()).isEqualTo(BackupTransport.TRANSPORT_ERROR);
+    }
+
+    @Test
+    public void testStateCompromised_whenCauseInstanceOfTaskException() {
+        Exception cause = TaskException.forStatus(BackupTransport.TRANSPORT_NOT_INITIALIZED);
+
+        TaskException exception = TaskException.stateCompromised(cause);
+
+        assertThat(exception.isStateCompromised()).isTrue();
+        assertThat(exception.getStatus()).isEqualTo(BackupTransport.TRANSPORT_NOT_INITIALIZED);
+        assertThat(exception.getCause()).isEqualTo(cause);
+    }
+
+    @Test
+    public void testStateCompromised_whenCauseNotInstanceOfTaskException() {
+        Exception cause = new IOException();
+
+        TaskException exception = TaskException.stateCompromised(cause);
+
+        assertThat(exception.isStateCompromised()).isTrue();
+        assertThat(exception.getStatus()).isEqualTo(BackupTransport.TRANSPORT_ERROR);
+        assertThat(exception.getCause()).isEqualTo(cause);
+    }
+
+    @Test
+    public void testForStatus_whenTransportOk_throws() {
+        expectThrows(
+                IllegalArgumentException.class,
+                () -> TaskException.forStatus(BackupTransport.TRANSPORT_OK));
+    }
+
+    @Test
+    public void testForStatus_whenTransportNotInitialized() {
+        TaskException exception =
+                TaskException.forStatus(BackupTransport.TRANSPORT_NOT_INITIALIZED);
+
+        assertThat(exception.isStateCompromised()).isFalse();
+        assertThat(exception.getStatus()).isEqualTo(BackupTransport.TRANSPORT_NOT_INITIALIZED);
+    }
+
+    @Test
+    public void testCausedBy_whenCauseInstanceOfTaskException_returnsCause() {
+        Exception cause = TaskException.forStatus(BackupTransport.TRANSPORT_NOT_INITIALIZED);
+
+        TaskException exception = TaskException.causedBy(cause);
+
+        assertThat(exception).isEqualTo(cause);
+    }
+
+    @Test
+    public void testCausedBy_whenCauseNotInstanceOfTaskException() {
+        Exception cause = new IOException();
+
+        TaskException exception = TaskException.causedBy(cause);
+
+        assertThat(exception).isNotEqualTo(cause);
+        assertThat(exception.isStateCompromised()).isFalse();
+        assertThat(exception.getStatus()).isEqualTo(BackupTransport.TRANSPORT_ERROR);
+        assertThat(exception.getCause()).isEqualTo(cause);
+    }
+
+    @Test
+    public void testCreate() {
+        TaskException exception = TaskException.create();
+
+        assertThat(exception.isStateCompromised()).isFalse();
+        assertThat(exception.getStatus()).isEqualTo(BackupTransport.TRANSPORT_ERROR);
+    }
+
+    @Test
+    public void testIsStateCompromised_whenStateCompromised_returnsTrue() {
+        TaskException taskException = TaskException.stateCompromised();
+
+        boolean stateCompromised = taskException.isStateCompromised();
+
+        assertThat(stateCompromised).isTrue();
+    }
+
+    @Test
+    public void testIsStateCompromised_whenCreatedWithCreate_returnsFalse() {
+        TaskException taskException = TaskException.create();
+
+        boolean stateCompromised = taskException.isStateCompromised();
+
+        assertThat(stateCompromised).isFalse();
+    }
+
+    @Test
+    public void testGetStatus_whenStatusIsTransportPackageRejected() {
+        TaskException taskException =
+                TaskException.forStatus(BackupTransport.TRANSPORT_PACKAGE_REJECTED);
+
+        int status = taskException.getStatus();
+
+        assertThat(status).isEqualTo(BackupTransport.TRANSPORT_PACKAGE_REJECTED);
+    }
+
+    @Test
+    public void testGetStatus_whenStatusIsTransportNotInitialized() {
+        TaskException taskException =
+                TaskException.forStatus(BackupTransport.TRANSPORT_NOT_INITIALIZED);
+
+        int status = taskException.getStatus();
+
+        assertThat(status).isEqualTo(BackupTransport.TRANSPORT_NOT_INITIALIZED);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityGestureDetectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityGestureDetectorTest.java
index 1c025cf..aad7230 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityGestureDetectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityGestureDetectorTest.java
@@ -18,23 +18,22 @@
 
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.when;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.accessibilityservice.AccessibilityService;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Point;
 import android.graphics.PointF;
-import android.os.Looper;
 import android.util.DisplayMetrics;
 import android.view.GestureDetector;
 import android.view.MotionEvent;
-import java.util.ArrayList;
+
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 
+import java.util.ArrayList;
 
 /**
  * Tests for AccessibilityGestureDetector
@@ -50,14 +49,6 @@
     private AccessibilityGestureDetector mDetector;
     private AccessibilityGestureDetector.Listener mResultListener;
 
-
-    @BeforeClass
-    public static void oneTimeInitialization() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-    }
-
     @Before
     public void setUp() {
         // Construct a mock Context.
@@ -67,7 +58,6 @@
         Resources mockResources = mock(Resources.class);
         when(mockResources.getDisplayMetrics()).thenReturn(displayMetricsMock);
         Context contextMock = mock(Context.class);
-        when(contextMock.getMainLooper()).thenReturn(Looper.myLooper());
         when(contextMock.getResources()).thenReturn(mockResources);
 
         // Construct a testable AccessibilityGestureDetector.
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerTest.java
index 4c0f38a..b9b6d55 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerTest.java
@@ -29,7 +29,6 @@
 
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.app.Instrumentation;
-import android.os.Looper;
 import android.os.UserHandle;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
@@ -41,8 +40,8 @@
 
 import com.android.internal.util.IntPair;
 
+import org.junit.After;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -63,13 +62,6 @@
     private MessageCapturingHandler mHandler;
     private Instrumentation mInstrumentation;
 
-    @BeforeClass
-    public static void oneTimeInitialization() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-    }
-
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
@@ -77,6 +69,12 @@
         mInstrumentation = InstrumentationRegistry.getInstrumentation();
     }
 
+    @After
+    public void tearDown() {
+        mHandler.removeAllMessages();
+    }
+
+
     private AccessibilityManager createManager(boolean enabled) throws Exception {
         long serviceReturnValue = IntPair.of(
                 (enabled) ? AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED : 0,
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
index 412e844..66d9345 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
@@ -33,16 +33,14 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.os.Handler;
 import android.os.IBinder;
-import android.os.Looper;
 import android.os.RemoteException;
 import android.os.UserHandle;
 
 import com.android.server.wm.WindowManagerInternal;
 
+import org.junit.After;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -74,13 +72,6 @@
 
     MessageCapturingHandler mHandler = new MessageCapturingHandler(null);
 
-    @BeforeClass
-    public static void oneTimeInitialization() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-    }
-
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
@@ -98,6 +89,12 @@
                 mMockGlobalActionPerformer);
     }
 
+    @After
+    public void tearDown() {
+        mHandler.removeAllMessages();
+    }
+
+
     @Test
     public void bind_requestsContextToBindService() {
         mConnection.bindLocked();
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureControllerTest.java
index a3decb9..44a514f 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureControllerTest.java
@@ -16,19 +16,8 @@
 
 package com.android.server.accessibility;
 
-import android.accessibilityservice.FingerprintGestureController;
-import android.accessibilityservice.FingerprintGestureController.FingerprintGestureCallback;
-import android.accessibilityservice.IAccessibilityServiceConnection;
-import android.os.Looper;
-import android.support.test.filters.FlakyTest;
-
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import static android.accessibilityservice.FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_DOWN;
+import static android.accessibilityservice.FingerprintGestureController
+        .FINGERPRINT_GESTURE_SWIPE_DOWN;
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -38,6 +27,15 @@
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
+import android.accessibilityservice.FingerprintGestureController;
+import android.accessibilityservice.FingerprintGestureController.FingerprintGestureCallback;
+import android.accessibilityservice.IAccessibilityServiceConnection;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
 /**
  * Tests for FingerprintGestureController.
  * TODO: These tests aren't really for server code, so this isn't their ideal home.
@@ -47,13 +45,6 @@
     @Mock FingerprintGestureCallback mMockFingerprintGestureCallback;
     FingerprintGestureController mFingerprintGestureController;
 
-    @BeforeClass
-    public static void oneTimeInitialization() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-    }
-
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
@@ -97,7 +88,6 @@
     }
 
     @Test
-    @FlakyTest
     public void testDetectionActiveCallback_withHandler_shouldPostRunnableToHandler() {
         MessageCapturingHandler messageCapturingHandler = new MessageCapturingHandler((message) -> {
             message.getCallback().run();
@@ -127,6 +117,8 @@
         mFingerprintGestureController.onGestureDetectionActiveChanged(false);
         assertFalse(messageCapturingHandler.hasMessages());
         verifyZeroInteractions(mMockFingerprintGestureCallback);
+
+        messageCapturingHandler.removeAllMessages();
     }
 
     @Test
@@ -145,7 +137,6 @@
     }
 
     @Test
-    @FlakyTest
     public void testGestureCallback_withHandler_shouldPostRunnableToHandler() {
         MessageCapturingHandler messageCapturingHandler = new MessageCapturingHandler((message) -> {
             message.getCallback().run();
@@ -167,5 +158,7 @@
         mFingerprintGestureController.onGesture(FINGERPRINT_GESTURE_SWIPE_DOWN);
         assertFalse(messageCapturingHandler.hasMessages());
         verifyZeroInteractions(mMockFingerprintGestureCallback);
+
+        messageCapturingHandler.removeAllMessages();
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureDispatcherTest.java b/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureDispatcherTest.java
index 6ce7bbe..de7bc44 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureDispatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureDispatcherTest.java
@@ -16,25 +16,6 @@
 
 package com.android.server.accessibility;
 
-import android.accessibilityservice.FingerprintGestureController;
-import android.content.res.Resources;
-import android.hardware.fingerprint.IFingerprintService;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.view.KeyEvent;
-
-import com.android.server.accessibility.FingerprintGestureDispatcher.FingerprintGestureClient;
-
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.Arrays;
-import java.util.Collections;
-
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.anyBoolean;
@@ -44,6 +25,22 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
+import android.accessibilityservice.FingerprintGestureController;
+import android.content.res.Resources;
+import android.hardware.fingerprint.IFingerprintService;
+import android.view.KeyEvent;
+
+import com.android.server.accessibility.FingerprintGestureDispatcher.FingerprintGestureClient;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Arrays;
+import java.util.Collections;
+
 /**
  * Tests for FingerprintGestureDispatcher
  */
@@ -57,13 +54,6 @@
     private MessageCapturingHandler mMessageCapturingHandler;
     private FingerprintGestureDispatcher mFingerprintGestureDispatcher;
 
-    @BeforeClass
-    public static void oneTimeInitialization() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-    }
-
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
@@ -77,6 +67,12 @@
         when(mGestureCapturingClient.isCapturingFingerprintGestures()).thenReturn(true);
     }
 
+    @After
+    public void tearDown() {
+        mMessageCapturingHandler.removeAllMessages();
+    }
+
+
     @Test
     public void testNoServices_doesNotCrashOrConsumeGestures() {
         mFingerprintGestureDispatcher.onClientActiveChanged(true);
@@ -171,7 +167,7 @@
     }
 
     @Test
-    public void ifGestureDectionNotSupported_neverSaysAvailable() throws Exception {
+    public void ifGestureDetectionNotSupported_neverSaysAvailable() throws Exception {
         when(mMockResources.getBoolean(anyInt())).thenReturn(false);
         // Need to create a new dispatcher, since it picks up the resource value in its
         // constructor. This is fine since hardware config values don't change dynamically.
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java b/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java
index 236b458..23ce483 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java
@@ -40,6 +40,7 @@
 import android.os.RemoteException;
 import android.view.KeyEvent;
 
+import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.accessibility.KeyEventDispatcher.KeyEventFilter;
@@ -47,16 +48,14 @@
 
 import org.hamcrest.Description;
 import org.hamcrest.TypeSafeMatcher;
+import org.junit.After;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.List;
 
 /**
  * Tests for KeyEventDispatcher
@@ -68,7 +67,7 @@
     private final KeyEvent mKeyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, 0x40);
     private final KeyEvent mOtherKeyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, 0x50);
     private final Object mLock = new Object();
-    private MessageCapturingHandler mInputEventsHander;
+    private MessageCapturingHandler mInputEventsHandler;
     private KeyEventDispatcher mKeyEventDispatcher;
     private KeyEventFilter mKeyEventFilter1;
     private KeyEventFilter mKeyEventFilter2;
@@ -77,23 +76,17 @@
     private ArgumentCaptor<Integer> mFilter1SequenceCaptor = ArgumentCaptor.forClass(Integer.class);
     private ArgumentCaptor<Integer> mFilter2SequenceCaptor = ArgumentCaptor.forClass(Integer.class);
 
-    @BeforeClass
-    public static void oneTimeInitialization() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-    }
-
     @Before
     public void setUp() {
-        mInputEventsHander = new MessageCapturingHandler();
+        Looper looper = InstrumentationRegistry.getContext().getMainLooper();
+        mInputEventsHandler = new MessageCapturingHandler(looper, null);
         mMockPowerManagerService = mock(IPowerManager.class);
         // TODO: It would be better to mock PowerManager rather than its binder, but the class is
         // final.
         PowerManager powerManager =
-                new PowerManager(mock(Context.class), mMockPowerManagerService, new Handler());
-        mMessageCapturingHandler = new MessageCapturingHandler();
-        mKeyEventDispatcher = new KeyEventDispatcher(mInputEventsHander, SEND_FRAMEWORK_KEY_EVENT,
+                new PowerManager(mock(Context.class), mMockPowerManagerService, new Handler(looper));
+        mMessageCapturingHandler = new MessageCapturingHandler(looper, null);
+        mKeyEventDispatcher = new KeyEventDispatcher(mInputEventsHandler, SEND_FRAMEWORK_KEY_EVENT,
                 mLock, powerManager, mMessageCapturingHandler);
 
         mKeyEventFilter1 = mock(KeyEventFilter.class);
@@ -107,10 +100,17 @@
                 .thenReturn(true);
     }
 
+    @After
+    public void tearDown() {
+        mInputEventsHandler.removeAllMessages();
+        mMessageCapturingHandler.removeAllMessages();
+    }
+
+
     @Test
     public void testNotifyKeyEvent_withNoBoundServices_shouldReturnFalse() {
         assertFalse(mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Collections.EMPTY_LIST));
-        assertFalse(mMessageCapturingHandler.isTimeoutPending());
+        assertFalse(isTimeoutPending(mMessageCapturingHandler));
     }
 
     @Test
@@ -119,7 +119,7 @@
         when(keyEventFilter.onKeyEvent((KeyEvent) anyObject(), anyInt())).thenReturn(false);
         assertFalse(mKeyEventDispatcher
                 .notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(keyEventFilter)));
-        assertFalse(mMessageCapturingHandler.isTimeoutPending());
+        assertFalse(isTimeoutPending(mMessageCapturingHandler));
     }
 
     @Test
@@ -152,9 +152,9 @@
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
                 mFilter1SequenceCaptor.getValue());
 
-        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
         verifyZeroInteractions(mMockPowerManagerService);
-        assertFalse(mMessageCapturingHandler.isTimeoutPending());
+        assertFalse(isTimeoutPending(mMessageCapturingHandler));
     }
 
     @Test
@@ -166,10 +166,10 @@
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true,
                 mFilter1SequenceCaptor.getValue());
 
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
         verify(mMockPowerManagerService, times(1)).userActivity(anyLong(),
                 eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
-        assertFalse(mMessageCapturingHandler.isTimeoutPending());
+        assertFalse(isTimeoutPending(mMessageCapturingHandler));
     }
 
     @Test
@@ -182,9 +182,9 @@
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false,
                 mFilter2SequenceCaptor.getValue());
 
-        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
         verifyZeroInteractions(mMockPowerManagerService);
-        assertFalse(mMessageCapturingHandler.isTimeoutPending());
+        assertFalse(isTimeoutPending(mMessageCapturingHandler));
     }
 
     @Test
@@ -198,10 +198,10 @@
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, true,
                 mFilter2SequenceCaptor.getValue());
 
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
         verify(mMockPowerManagerService, times(1)).userActivity(anyLong(),
                 eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
-        assertFalse(mMessageCapturingHandler.isTimeoutPending());
+        assertFalse(isTimeoutPending(mMessageCapturingHandler));
     }
 
     @Test
@@ -215,10 +215,10 @@
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false,
                 mFilter2SequenceCaptor.getValue());
 
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
         verify(mMockPowerManagerService, times(1)).userActivity(anyLong(),
                 eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
-        assertFalse(mMessageCapturingHandler.isTimeoutPending());
+        assertFalse(isTimeoutPending(mMessageCapturingHandler));
     }
 
     @Test
@@ -232,10 +232,10 @@
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, true,
                 mFilter2SequenceCaptor.getValue());
 
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
         verify(mMockPowerManagerService, times(1)).userActivity(anyLong(),
                 eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
-        assertFalse(mMessageCapturingHandler.isTimeoutPending());
+        assertFalse(isTimeoutPending(mMessageCapturingHandler));
     }
 
     // Each event should have its result set only once, but if it's set twice, we should ignore
@@ -249,14 +249,14 @@
                 mFilter1SequenceCaptor.getValue());
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
                 mFilter1SequenceCaptor.getValue());
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
 
         // Verify event is sent properly when other service responds
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false,
                 mFilter2SequenceCaptor.getValue());
-        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
         verifyZeroInteractions(mMockPowerManagerService);
-        assertFalse(mMessageCapturingHandler.isTimeoutPending());
+        assertFalse(isTimeoutPending(mMessageCapturingHandler));
     }
 
 
@@ -269,9 +269,9 @@
                 mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2));
 
         assertEquals(1, mMessageCapturingHandler.timedMessages.size());
-        mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0));
+        mKeyEventDispatcher.handleMessage(getTimedMessage(mMessageCapturingHandler, 0));
 
-        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
         verifyZeroInteractions(mMockPowerManagerService);
     }
 
@@ -284,9 +284,9 @@
                 mFilter1SequenceCaptor.getValue());
 
         assertEquals(1, mMessageCapturingHandler.timedMessages.size());
-        mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0));
+        mKeyEventDispatcher.handleMessage(getTimedMessage(mMessageCapturingHandler, 0));
 
-        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
         verifyZeroInteractions(mMockPowerManagerService);
     }
 
@@ -300,9 +300,9 @@
                 mFilter1SequenceCaptor.getValue());
 
         assertEquals(1, mMessageCapturingHandler.timedMessages.size());
-        mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0));
+        mKeyEventDispatcher.handleMessage(getTimedMessage(mMessageCapturingHandler, 0));
 
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
         verify(mMockPowerManagerService, times(1)).userActivity(anyLong(),
                 eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
     }
@@ -310,34 +310,34 @@
     @Test
     public void testEventTimesOut_thenServiceReturnsFalse_shouldPassToFrameworkOnce() {
         mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
 
         assertEquals(1, mMessageCapturingHandler.timedMessages.size());
-        mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0));
-        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        mKeyEventDispatcher.handleMessage(getTimedMessage(mMessageCapturingHandler, 0));
+        assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
 
-        mInputEventsHander.removeMessages(SEND_FRAMEWORK_KEY_EVENT);
+        mInputEventsHandler.removeMessages(SEND_FRAMEWORK_KEY_EVENT);
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
                 mFilter1SequenceCaptor.getValue());
 
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
         verifyZeroInteractions(mMockPowerManagerService);
     }
 
     @Test
     public void testEventTimesOut_afterServiceReturnsFalse_shouldPassToFrameworkOnce() {
         mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
 
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
                 mFilter1SequenceCaptor.getValue());
-        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
 
-        mInputEventsHander.removeMessages(SEND_FRAMEWORK_KEY_EVENT);
+        mInputEventsHandler.removeMessages(SEND_FRAMEWORK_KEY_EVENT);
         assertEquals(1, mMessageCapturingHandler.timedMessages.size());
-        mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0));
+        mKeyEventDispatcher.handleMessage(getTimedMessage(mMessageCapturingHandler, 0));
 
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
         verifyZeroInteractions(mMockPowerManagerService);
     }
 
@@ -349,9 +349,9 @@
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true,
                 mFilter1SequenceCaptor.getValue());
         assertEquals(1, mMessageCapturingHandler.timedMessages.size());
-        mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0));
+        mKeyEventDispatcher.handleMessage(getTimedMessage(mMessageCapturingHandler, 0));
 
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
         verify(mMockPowerManagerService, times(1)).userActivity(anyLong(),
                 eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
     }
@@ -362,11 +362,11 @@
     @Test
     public void testFlushService_withPendingEvent_shouldPassToFramework() {
         mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
 
         mKeyEventDispatcher.flush(mKeyEventFilter1);
 
-        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
     }
 
     @Test
@@ -377,7 +377,7 @@
         mKeyEventDispatcher.flush(mKeyEventFilter1);
         mKeyEventDispatcher.flush(mKeyEventFilter2);
 
-        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
     }
 
     @Test
@@ -389,7 +389,7 @@
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, true,
                 mFilter2SequenceCaptor.getValue());
 
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
     }
 
     @Test
@@ -401,7 +401,7 @@
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false,
                 mFilter2SequenceCaptor.getValue());
 
-        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
     }
 
     @Test
@@ -417,11 +417,11 @@
         mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
         mKeyEventDispatcher
                 .notifyKeyEventLocked(mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
 
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
                 mFilter1SequenceCaptor.getAllValues().get(0));
-        mInputEventsHander.removeMessages(SEND_FRAMEWORK_KEY_EVENT);
+        mInputEventsHandler.removeMessages(SEND_FRAMEWORK_KEY_EVENT);
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
                 mFilter1SequenceCaptor.getAllValues().get(1));
 
@@ -433,14 +433,14 @@
         mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
         mKeyEventDispatcher
                 .notifyKeyEventLocked(mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
 
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true,
                 mFilter1SequenceCaptor.getAllValues().get(0));
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true,
                 mFilter1SequenceCaptor.getAllValues().get(1));
 
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
     }
 
     @Test
@@ -448,7 +448,7 @@
         mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
         mKeyEventDispatcher
                 .notifyKeyEventLocked(mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
 
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true,
                 mFilter1SequenceCaptor.getAllValues().get(0));
@@ -463,7 +463,7 @@
         mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
         mKeyEventDispatcher
                 .notifyKeyEventLocked(mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
 
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
                 mFilter1SequenceCaptor.getAllValues().get(0));
@@ -478,9 +478,9 @@
         mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
         mKeyEventDispatcher
                 .notifyKeyEventLocked(mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
 
-        mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0));
+        mKeyEventDispatcher.handleMessage(getTimedMessage(mMessageCapturingHandler, 0));
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true,
                 mFilter1SequenceCaptor.getAllValues().get(0));
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true,
@@ -494,7 +494,7 @@
         mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
         mKeyEventDispatcher.notifyKeyEventLocked(
                 mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2));
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
 
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false,
                 mFilter2SequenceCaptor.getValue());
@@ -513,7 +513,7 @@
         mKeyEventDispatcher.flush(mKeyEventFilter1);
         mKeyEventDispatcher.notifyKeyEventLocked(
                 mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter2));
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
 
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false,
                 mFilter2SequenceCaptor.getAllValues().get(0));
@@ -543,24 +543,34 @@
     }
 
     private void assertOneKeyEventSentToFramework(KeyEvent event) {
-        assertEquals(1, mInputEventsHander.timedMessages.size());
-        assertEquals(SEND_FRAMEWORK_KEY_EVENT, mInputEventsHander.timedMessages.get(0).what);
-        assertEquals(WindowManagerPolicy.FLAG_PASS_TO_USER,
-                mInputEventsHander.timedMessages.get(0).arg1);
-        assertTrue(new KeyEventMatcher(event).matches(mInputEventsHander.timedMessages.get(0).obj));
+        assertEquals(1, mInputEventsHandler.timedMessages.size());
+
+        Message m = getTimedMessage(mInputEventsHandler, 0);
+        assertEquals(SEND_FRAMEWORK_KEY_EVENT, m.what);
+        assertEquals(WindowManagerPolicy.FLAG_PASS_TO_USER, m.arg1);
+        assertTrue(new KeyEventMatcher(event).matches(m.obj));
     }
 
     private void assertTwoKeyEventsSentToFrameworkInOrder(KeyEvent first, KeyEvent second) {
-        assertEquals(2, mInputEventsHander.timedMessages.size());
-        assertEquals(SEND_FRAMEWORK_KEY_EVENT, mInputEventsHander.timedMessages.get(0).what);
-        assertEquals(WindowManagerPolicy.FLAG_PASS_TO_USER,
-                mInputEventsHander.timedMessages.get(0).arg1);
-        assertTrue(new KeyEventMatcher(first).matches(mInputEventsHander.timedMessages.get(0).obj));
-        assertEquals(SEND_FRAMEWORK_KEY_EVENT, mInputEventsHander.timedMessages.get(1).what);
-        assertEquals(WindowManagerPolicy.FLAG_PASS_TO_USER,
-                mInputEventsHander.timedMessages.get(1).arg1);
-        assertTrue(new KeyEventMatcher(second)
-                .matches(mInputEventsHander.timedMessages.get(1).obj));
+        assertEquals(2, mInputEventsHandler.timedMessages.size());
+
+        Message m0 = getTimedMessage(mInputEventsHandler, 0);
+        assertEquals(SEND_FRAMEWORK_KEY_EVENT, m0.what);
+        assertEquals(WindowManagerPolicy.FLAG_PASS_TO_USER, m0.arg1);
+        assertTrue(new KeyEventMatcher(first).matches(m0.obj));
+
+        Message m1 = getTimedMessage(mInputEventsHandler, 1);
+        assertEquals(SEND_FRAMEWORK_KEY_EVENT, m1.what);
+        assertEquals(WindowManagerPolicy.FLAG_PASS_TO_USER, m1.arg1);
+        assertTrue(new KeyEventMatcher(second).matches(m1.obj));
+    }
+
+    private static Message getTimedMessage(MessageCapturingHandler handler, int i) {
+        return handler.timedMessages.get(i).first;
+    }
+
+    private static boolean isTimeoutPending(MessageCapturingHandler handler) {
+        return handler.hasMessages(KeyEventDispatcher.MSG_ON_KEY_EVENT_TIMEOUT);
     }
 
     private class KeyEventMatcher extends TypeSafeMatcher<KeyEvent> {
@@ -581,18 +591,4 @@
             description.appendText("Key event matcher");
         }
     }
-
-    private class MessageCapturingHandler extends Handler {
-        List<Message> timedMessages = new ArrayList<>();
-
-        @Override
-        public boolean sendMessageAtTime(Message message, long uptimeMillis) {
-            timedMessages.add(Message.obtain(message));
-            return super.sendMessageAtTime(message, uptimeMillis);
-        }
-
-        public boolean isTimeoutPending() {
-            return hasMessages(KeyEventDispatcher.MSG_ON_KEY_EVENT_TIMEOUT);
-        }
-    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/KeyboardInterceptorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/KeyboardInterceptorTest.java
index 851e221..9926a09 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/KeyboardInterceptorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/KeyboardInterceptorTest.java
@@ -28,7 +28,6 @@
 import static org.mockito.Mockito.when;
 import static org.mockito.hamcrest.MockitoHamcrest.argThat;
 
-import android.os.Looper;
 import android.view.KeyEvent;
 
 import androidx.test.runner.AndroidJUnit4;
@@ -38,8 +37,8 @@
 
 import org.hamcrest.Description;
 import org.hamcrest.TypeSafeMatcher;
+import org.junit.After;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InOrder;
@@ -58,19 +57,18 @@
     @Mock AccessibilityManagerService mMockAms;
     @Mock WindowManagerPolicy mMockPolicy;
 
-    @BeforeClass
-    public static void oneTimeInitialization() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-    }
-
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mInterceptor = new KeyboardInterceptor(mMockAms, mMockPolicy, mHandler);
     }
 
+    @After
+    public void tearDown() {
+        mHandler.removeAllMessages();
+    }
+
+
     @Test
     public void whenNonspecialKeyArrives_withNothingInQueue_eventGoesToAms() {
         KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java
index d6d21c6..c88b873 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java
@@ -43,9 +43,9 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.support.test.filters.FlakyTest;
 import android.view.MagnificationSpec;
 
+import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.R;
@@ -55,8 +55,8 @@
 import org.hamcrest.CoreMatchers;
 import org.hamcrest.Description;
 import org.hamcrest.TypeSafeMatcher;
+import org.junit.After;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -67,7 +67,6 @@
 import java.util.Locale;
 
 @RunWith(AndroidJUnit4.class)
-@FlakyTest
 public class MagnificationControllerTest {
     static final Rect INITIAL_MAGNIFICATION_BOUNDS = new Rect(0, 0, 100, 200);
     static final PointF INITIAL_MAGNIFICATION_BOUNDS_CENTER = new PointF(
@@ -75,8 +74,10 @@
     static final PointF INITIAL_BOUNDS_UPPER_LEFT_2X_CENTER = new PointF(25, 50);
     static final PointF INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER = new PointF(75, 150);
     static final Rect OTHER_MAGNIFICATION_BOUNDS = new Rect(100, 200, 500, 600);
+    static final Rect OTHER_MAGNIFICATION_BOUNDS_COMPAT = new Rect(50, 100, 450, 500);
     static final PointF OTHER_BOUNDS_LOWER_RIGHT_2X_CENTER = new PointF(400, 500);
     static final Region INITIAL_MAGNIFICATION_REGION = new Region(INITIAL_MAGNIFICATION_BOUNDS);
+    static final Region OTHER_REGION_COMPAT = new Region(OTHER_MAGNIFICATION_BOUNDS_COMPAT);
     static final Region OTHER_REGION = new Region(OTHER_MAGNIFICATION_BOUNDS);
     static final int SERVICE_ID_1 = 1;
     static final int SERVICE_ID_2 = 2;
@@ -91,25 +92,17 @@
             return mMagnificationController.handleMessage(msg);
         }
     });
-    final ArgumentCaptor<MagnificationSpec> mMagnificationSpecCaptor =
-            ArgumentCaptor.forClass(MagnificationSpec.class);
     final ValueAnimator mMockValueAnimator = mock(ValueAnimator.class);
     MagnificationController.SettingsBridge mMockSettingsBridge;
 
-
     MagnificationController mMagnificationController;
     ValueAnimator.AnimatorUpdateListener mTargetAnimationListener;
 
-    @BeforeClass
-    public static void oneTimeInitialization() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-    }
-
     @Before
     public void setUp() {
-        when(mMockContext.getMainLooper()).thenReturn(Looper.myLooper());
+        Looper looper = InstrumentationRegistry.getContext().getMainLooper();
+        // Pretending ID of the Thread associated with looper as main thread ID in controller
+        when(mMockContext.getMainLooper()).thenReturn(looper);
         Resources mockResources = mock(Resources.class);
         when(mMockContext.getResources()).thenReturn(mockResources);
         when(mockResources.getInteger(R.integer.config_longAnimTime))
@@ -136,6 +129,12 @@
         Mockito.reset(mMockValueAnimator); // Ignore other initialization
     }
 
+    @After
+    public void tearDown() {
+        mMessageCapturingHandler.removeAllMessages();
+    }
+
+
     @Test
     public void testRegister_WindowManagerAndContextRegisterListeners() {
         mMagnificationController.register();
@@ -202,6 +201,7 @@
         final PointF offsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, center, scale);
         assertTrue(mMagnificationController
                 .setScale(scale, center.x, center.y, false, SERVICE_ID_1));
+        mMessageCapturingHandler.sendAllMessages();
 
         final MagnificationSpec expectedSpec = getMagnificationSpec(scale, offsets);
         verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(expectedSpec)));
@@ -219,6 +219,7 @@
         PointF pivotPoint = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
         assertTrue(mMagnificationController
                 .setScale(scale, pivotPoint.x, pivotPoint.y, true, SERVICE_ID_1));
+        mMessageCapturingHandler.sendAllMessages();
 
         // New center should be halfway between original center and pivot
         PointF newCenter = new PointF((pivotPoint.x + INITIAL_MAGNIFICATION_BOUNDS.centerX()) / 2,
@@ -264,6 +265,7 @@
         PointF newCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
         assertTrue(mMagnificationController
                 .setCenter(newCenter.x, newCenter.y, false, SERVICE_ID_1));
+        mMessageCapturingHandler.sendAllMessages();
         PointF expectedOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale);
         MagnificationSpec expectedSpec = getMagnificationSpec(scale, expectedOffsets);
 
@@ -284,6 +286,7 @@
 
         assertTrue(mMagnificationController.setScaleAndCenter(scale, newCenter.x, newCenter.y,
                 true, SERVICE_ID_1));
+        mMessageCapturingHandler.sendAllMessages();
 
         assertEquals(newCenter.x, mMagnificationController.getCenterX(), 0.5);
         assertEquals(newCenter.y, mMagnificationController.getCenterY(), 0.5);
@@ -325,6 +328,7 @@
         assertTrue(mMagnificationController.setScaleAndCenter(
                 MagnificationController.MAX_SCALE + 1.0f,
                 newCenter.x, newCenter.y, false, SERVICE_ID_1));
+        mMessageCapturingHandler.sendAllMessages();
 
         assertEquals(newCenter.x, mMagnificationController.getCenterX(), 0.5);
         assertEquals(newCenter.y, mMagnificationController.getCenterY(), 0.5);
@@ -335,6 +339,7 @@
         assertTrue(mMagnificationController.setScaleAndCenter(0.5f,
                 INITIAL_MAGNIFICATION_BOUNDS_CENTER.x, INITIAL_MAGNIFICATION_BOUNDS_CENTER.y,
                 false, SERVICE_ID_1));
+        mMessageCapturingHandler.sendAllMessages();
 
         assertEquals(INITIAL_MAGNIFICATION_BOUNDS_CENTER.x,
                 mMagnificationController.getCenterX(), 0.5);
@@ -351,6 +356,7 @@
         // Off the edge to the top and left
         assertTrue(mMagnificationController.setScaleAndCenter(
                 scale, -100f, -200f, false, SERVICE_ID_1));
+        mMessageCapturingHandler.sendAllMessages();
 
         PointF newCenter = INITIAL_BOUNDS_UPPER_LEFT_2X_CENTER;
         PointF newOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale);
@@ -364,6 +370,7 @@
         assertTrue(mMagnificationController.setScaleAndCenter(scale,
                 INITIAL_MAGNIFICATION_BOUNDS.right + 1, INITIAL_MAGNIFICATION_BOUNDS.bottom + 1,
                 false, SERVICE_ID_1));
+        mMessageCapturingHandler.sendAllMessages();
         newCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
         newOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale);
         assertEquals(newCenter.x, mMagnificationController.getCenterX(), 0.5);
@@ -391,12 +398,14 @@
         // First zoom in
         assertTrue(mMagnificationController
                 .setScaleAndCenter(scale, startCenter.x, startCenter.y, false, SERVICE_ID_1));
+        mMessageCapturingHandler.sendAllMessages();
         Mockito.reset(mMockWindowManager);
 
         PointF newCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
         PointF newOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale);
         mMagnificationController.offsetMagnifiedRegion(
                 startOffsets.x - newOffsets.x, startOffsets.y - newOffsets.y, SERVICE_ID_1);
+        mMessageCapturingHandler.sendAllMessages();
 
         MagnificationSpec expectedSpec = getMagnificationSpec(scale, newOffsets);
         verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(expectedSpec)));
@@ -490,6 +499,7 @@
     public void testResetIfNeeded_doesWhatItSays() {
         mMagnificationController.register();
         zoomIn2xToMiddle();
+        mMessageCapturingHandler.sendAllMessages();
         reset(mMockAms);
         assertTrue(mMagnificationController.resetIfNeeded(false));
         verify(mMockAms).notifyMagnificationChanged(
@@ -507,6 +517,7 @@
                 broadcastReceiverCaptor.capture(), (IntentFilter) anyObject());
         BroadcastReceiver br = broadcastReceiverCaptor.getValue();
         zoomIn2xToMiddle();
+        mMessageCapturingHandler.sendAllMessages();
         br.onReceive(mMockContext, null);
         mMessageCapturingHandler.sendAllMessages();
         assertFalse(mMagnificationController.isMagnifying());
@@ -517,6 +528,7 @@
         mMagnificationController.register();
         MagnificationCallbacks callbacks = getMagnificationCallbacks();
         zoomIn2xToMiddle();
+        mMessageCapturingHandler.sendAllMessages();
         callbacks.onUserContextChanged();
         mMessageCapturingHandler.sendAllMessages();
         assertFalse(mMagnificationController.isMagnifying());
@@ -539,10 +551,11 @@
         // Going from a small region to a large one leads to no issues
         mMagnificationController.register();
         zoomIn2xToMiddle();
+        mMessageCapturingHandler.sendAllMessages();
         MagnificationSpec startSpec = getCurrentMagnificationSpec();
         MagnificationCallbacks callbacks = getMagnificationCallbacks();
         Mockito.reset(mMockWindowManager);
-        callbacks.onMagnificationRegionChanged(OTHER_REGION);
+        callbacks.onMagnificationRegionChanged(OTHER_REGION_COMPAT);
         mMessageCapturingHandler.sendAllMessages();
         assertThat(getCurrentMagnificationSpec(), closeTo(startSpec));
         verifyNoMoreInteractions(mMockWindowManager);
@@ -553,11 +566,12 @@
         mMagnificationController.register();
         PointF startCenter = INITIAL_MAGNIFICATION_BOUNDS_CENTER;
         float scale = 2.0f;
+        // setting animate parameter to true is differ from zoomIn2xToMiddle()
         mMagnificationController.setScale(scale, startCenter.x, startCenter.y, true, SERVICE_ID_1);
         MagnificationSpec startSpec = getCurrentMagnificationSpec();
         MagnificationCallbacks callbacks = getMagnificationCallbacks();
         Mockito.reset(mMockWindowManager);
-        callbacks.onMagnificationRegionChanged(OTHER_REGION);
+        callbacks.onMagnificationRegionChanged(OTHER_REGION_COMPAT);
         mMessageCapturingHandler.sendAllMessages();
         assertThat(getCurrentMagnificationSpec(), closeTo(startSpec));
         verifyNoMoreInteractions(mMockWindowManager);
@@ -573,6 +587,7 @@
         PointF startCenter = OTHER_BOUNDS_LOWER_RIGHT_2X_CENTER;
         float scale = 2.0f;
         mMagnificationController.setScale(scale, startCenter.x, startCenter.y, false, SERVICE_ID_1);
+        mMessageCapturingHandler.sendAllMessages();
         MagnificationSpec startSpec = getCurrentMagnificationSpec();
         verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(startSpec)));
         Mockito.reset(mMockWindowManager);
@@ -597,8 +612,9 @@
         PointF startCenter = OTHER_BOUNDS_LOWER_RIGHT_2X_CENTER;
         float scale = 2.0f;
         mMagnificationController.setScale(scale, startCenter.x, startCenter.y, true, SERVICE_ID_1);
+        mMessageCapturingHandler.sendAllMessages();
         MagnificationSpec startSpec = getCurrentMagnificationSpec();
-        when (mMockValueAnimator.isRunning()).thenReturn(true);
+        when(mMockValueAnimator.isRunning()).thenReturn(true);
 
         callbacks.onMagnificationRegionChanged(INITIAL_MAGNIFICATION_REGION);
         mMessageCapturingHandler.sendAllMessages();
@@ -616,6 +632,7 @@
     public void testRequestRectOnScreen_rectAlreadyOnScreen_doesNothing() {
         mMagnificationController.register();
         zoomIn2xToMiddle();
+        mMessageCapturingHandler.sendAllMessages();
         MagnificationSpec startSpec = getCurrentMagnificationSpec();
         MagnificationCallbacks callbacks = getMagnificationCallbacks();
         Mockito.reset(mMockWindowManager);
@@ -631,6 +648,7 @@
     public void testRequestRectOnScreen_rectCanFitOnScreen_pansToGetRectOnScreen() {
         mMagnificationController.register();
         zoomIn2xToMiddle();
+        mMessageCapturingHandler.sendAllMessages();
         MagnificationCallbacks callbacks = getMagnificationCallbacks();
         Mockito.reset(mMockWindowManager);
         callbacks.onRectangleOnScreenRequested(0, 0, 1, 1);
@@ -644,6 +662,7 @@
     public void testRequestRectOnScreen_garbageInput_doesNothing() {
         mMagnificationController.register();
         zoomIn2xToMiddle();
+        mMessageCapturingHandler.sendAllMessages();
         MagnificationSpec startSpec = getCurrentMagnificationSpec();
         MagnificationCallbacks callbacks = getMagnificationCallbacks();
         Mockito.reset(mMockWindowManager);
@@ -653,12 +672,12 @@
         verifyNoMoreInteractions(mMockWindowManager);
     }
 
-
     @Test
     public void testRequestRectOnScreen_rectTooWide_pansToGetStartOnScreenBasedOnLocale() {
         Locale.setDefault(new Locale("en", "us"));
         mMagnificationController.register();
         zoomIn2xToMiddle();
+        mMessageCapturingHandler.sendAllMessages();
         MagnificationCallbacks callbacks = getMagnificationCallbacks();
         MagnificationSpec startSpec = getCurrentMagnificationSpec();
         Mockito.reset(mMockWindowManager);
@@ -685,6 +704,7 @@
     public void testRequestRectOnScreen_rectTooTall_pansMinimumToGetTopOnScreen() {
         mMagnificationController.register();
         zoomIn2xToMiddle();
+        mMessageCapturingHandler.sendAllMessages();
         MagnificationCallbacks callbacks = getMagnificationCallbacks();
         MagnificationSpec startSpec = getCurrentMagnificationSpec();
         Mockito.reset(mMockWindowManager);
@@ -708,6 +728,7 @@
 
         assertTrue(mMagnificationController.setScaleAndCenter(scale, firstCenter.x, firstCenter.y,
                 true, SERVICE_ID_1));
+        mMessageCapturingHandler.sendAllMessages();
 
         assertEquals(firstCenter.x, mMagnificationController.getCenterX(), 0.5);
         assertEquals(firstCenter.y, mMagnificationController.getCenterY(), 0.5);
@@ -736,6 +757,7 @@
                 scale, computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale));
         assertTrue(mMagnificationController.setCenter(
                 newCenter.x, newCenter.y, true, SERVICE_ID_1));
+        mMessageCapturingHandler.sendAllMessages();
 
         // Animation should have been restarted
         verify(mMockValueAnimator, times(2)).start();
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MessageCapturingHandler.java b/services/tests/servicestests/src/com/android/server/accessibility/MessageCapturingHandler.java
index e3ee47f..e2b517f 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MessageCapturingHandler.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MessageCapturingHandler.java
@@ -16,11 +16,13 @@
 
 package com.android.server.accessibility;
 
-import android.app.Notification;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
 import android.util.Pair;
 
+import androidx.test.InstrumentationRegistry;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -34,13 +36,22 @@
     Handler.Callback mCallback;
 
     public MessageCapturingHandler(Handler.Callback callback) {
+        this(InstrumentationRegistry.getContext().getMainLooper(), callback);
+    }
+
+    public MessageCapturingHandler(Looper looper, Callback callback) {
+        super(looper);
         mCallback = callback;
     }
 
+    /**
+     * Holding messages in queue, but never dispatching.
+     * @see #removeAllMessages()
+     */
     @Override
     public boolean sendMessageAtTime(Message message, long uptimeMillis) {
         timedMessages.add(new Pair<>(Message.obtain(message), uptimeMillis));
-        return super.sendMessageAtTime(message, uptimeMillis);
+        return super.sendMessageAtTime(message, Long.MAX_VALUE);
     }
 
     public void setCallback(Handler.Callback callback) {
@@ -67,6 +78,22 @@
         removeStaleMessages();
     }
 
+    /**
+     * Clear messages sent from this handler in queue.
+     * <p>
+     * If main looper is used, this method should be called in tear down function
+     * to ensure messages isolation between test cases.
+     * </p>
+     */
+    public void removeAllMessages() {
+        if (hasMessages()) {
+            for (int i = 0; i < timedMessages.size(); i++) {
+                Message message = timedMessages.get(i).first;
+                removeMessages(message.what, message.obj);
+            }
+        }
+    }
+
     public boolean hasMessages() {
         removeStaleMessages();
         return !timedMessages.isEmpty();
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
index 5f0fa87..2cba9d0 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
@@ -43,7 +43,6 @@
 import android.accessibilityservice.IAccessibilityServiceClient;
 import android.graphics.Point;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
 import android.util.Log;
@@ -57,8 +56,8 @@
 import org.hamcrest.Description;
 import org.hamcrest.Matcher;
 import org.hamcrest.TypeSafeMatcher;
+import org.junit.After;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -127,13 +126,6 @@
     Matcher<MotionEvent> mIsClickDown;
     Matcher<MotionEvent> mIsClickUp;
 
-    @BeforeClass
-    public static void oneTimeInitialization() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-    }
-
     @Before
     public void setUp() {
         mMessageCapturingHandler = new MessageCapturingHandler(new Handler.Callback() {
@@ -172,6 +164,12 @@
                 hasTimeFromDown(CLICK_DURATION));
     }
 
+    @After
+    public void tearDown() {
+        mMessageCapturingHandler.removeAllMessages();
+    }
+
+
     @Test
     public void testInjectEvents_shouldEmergeInOrderWithCorrectTiming() throws RemoteException {
         EventStreamTransformation next = attachMockNext(mMotionEventInjector);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/TouchExplorerTest.java
index c47885f..2645461 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/TouchExplorerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/TouchExplorerTest.java
@@ -16,12 +16,14 @@
 
 package com.android.server.accessibility;
 
-import static org.junit.Assert.assertTrue;
 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;
@@ -30,6 +32,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -66,6 +69,11 @@
     private TouchExplorer mTouchExplorer;
     private long mLastDownTime = Integer.MIN_VALUE;
 
+    // mock package-private AccessibilityGestureDetector class
+    @Rule
+    public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
+            new DexmakerShareClassLoaderRule();
+
     /**
      * {@link TouchExplorer#sendDownForAllNotInjectedPointers} injecting events with the same object
      * is resulting {@link ArgumentCaptor} to capture events with last state. Before implementation
@@ -93,8 +101,9 @@
     public void setUp() {
         Context context = InstrumentationRegistry.getContext();
         AccessibilityManagerService ams = new AccessibilityManagerService(context);
+        AccessibilityGestureDetector detector = mock(AccessibilityGestureDetector.class);
         mCaptor = new EventCaptor();
-        mTouchExplorer = new TouchExplorer(context, ams);
+        mTouchExplorer = new TouchExplorer(context, ams, detector);
         mTouchExplorer.setNext(mCaptor);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java
index 8853db2..8e09d60 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java
@@ -32,13 +32,12 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.os.IBinder;
-import android.os.Looper;
 import android.view.accessibility.AccessibilityEvent;
 
 import com.android.server.wm.WindowManagerInternal;
 
+import org.junit.After;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
@@ -66,13 +65,6 @@
     @Mock IAccessibilityServiceClient mMockAccessibilityServiceClient;
     @Mock IBinder mMockServiceAsBinder;
 
-    @BeforeClass
-    public static void oneTimeInitialization() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-    }
-
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
@@ -88,6 +80,12 @@
         mMessageCapturingHandler = new MessageCapturingHandler(null);
     }
 
+    @After
+    public void tearDown() {
+        mMessageCapturingHandler.removeAllMessages();
+    }
+
+
     @Test
     public void isRunning_returnsTrueOnlyWhenRunning() {
         assertFalse(mUiAutomationManager.isUiAutomationRunningLocked());
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index 47ce879..c44e492 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -258,7 +258,7 @@
         uidRec.hasInternetPermission = true;
         mAms.mActiveUids.put(uid, uidRec);
 
-        final ProcessRecord appRec = new ProcessRecord(mAms, new ApplicationInfo(), TAG, uid);
+        final ProcessRecord appRec = new ProcessRecord(mAms, new ApplicationInfo(), TAG, uid, null);
         appRec.thread = Mockito.mock(IApplicationThread.class);
         mAms.mLruProcesses.add(appRec);
 
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
index 2338744..ffc7fa2 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
@@ -69,7 +69,6 @@
 @Presubmit
 @RunWith(AndroidJUnit4.class)
 public class ActivityRecordTests extends ActivityTestsBase {
-    private ActivityTaskManagerService mService;
     private TestActivityStack mStack;
     private TaskRecord mTask;
     private ActivityRecord mActivity;
@@ -79,10 +78,10 @@
     public void setUp() throws Exception {
         super.setUp();
 
-        mService = createActivityTaskManagerService();
-        mStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
+        setupActivityTaskManagerService();
+        mStack = mSupervisor.getDefaultDisplay().createStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
-        mTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
+        mTask = new TaskBuilder(mSupervisor).setStack(mStack).build();
         mActivity = new ActivityBuilder(mService).setTask(mTask).build();
     }
 
@@ -189,17 +188,13 @@
 
     @Test
     public void testCanBeLaunchedOnDisplay() throws Exception {
-        testSupportsLaunchingResizeable(false /*taskPresent*/, true /*taskResizeable*/,
-                true /*activityResizeable*/, true /*expected*/);
+        mService.mSupportsMultiWindow = true;
+        final ActivityRecord activity = new ActivityBuilder(mService).build();
 
-        testSupportsLaunchingResizeable(false /*taskPresent*/, true /*taskResizeable*/,
-                false /*activityResizeable*/, false /*expected*/);
-
-        testSupportsLaunchingResizeable(true /*taskPresent*/, false /*taskResizeable*/,
-                true /*activityResizeable*/, false /*expected*/);
-
-        testSupportsLaunchingResizeable(true /*taskPresent*/, true /*taskResizeable*/,
-                false /*activityResizeable*/, true /*expected*/);
+        // An activity can be launched on default display.
+        assertTrue(activity.canBeLaunchedOnDisplay(DEFAULT_DISPLAY));
+        // An activity cannot be launched on a non-existent display.
+        assertFalse(activity.canBeLaunchedOnDisplay(DEFAULT_DISPLAY + 1));
     }
 
     @Test
@@ -230,26 +225,4 @@
         assertNull(mActivity.pendingOptions);
         assertNotNull(activity2.pendingOptions);
     }
-
-    private void testSupportsLaunchingResizeable(boolean taskPresent, boolean taskResizeable,
-            boolean activityResizeable, boolean expected) {
-        mService.mSupportsMultiWindow = true;
-
-        final TaskRecord task = taskPresent
-                ? new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build() : null;
-
-        if (task != null) {
-            task.setResizeMode(taskResizeable ? RESIZE_MODE_RESIZEABLE : RESIZE_MODE_UNRESIZEABLE);
-        }
-
-        final ActivityRecord record = new ActivityBuilder(mService).setTask(task).build();
-        record.info.resizeMode = activityResizeable
-                ? RESIZE_MODE_RESIZEABLE : RESIZE_MODE_UNRESIZEABLE;
-
-        record.canBeLaunchedOnDisplay(DEFAULT_DISPLAY);
-
-
-        verify(mService.mStackSupervisor, times(1)).canPlaceEntityOnDisplay(anyInt(), eq(expected),
-                anyInt(), anyInt(), eq(record.info));
-    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
index 1aa80c8..0345a81 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
@@ -64,8 +64,6 @@
 @Presubmit
 @RunWith(AndroidJUnit4.class)
 public class ActivityStackSupervisorTests extends ActivityTestsBase {
-    private ActivityTaskManagerService mService;
-    private ActivityStackSupervisor mSupervisor;
     private ActivityStack mFullscreenStack;
 
     @Before
@@ -73,8 +71,7 @@
     public void setUp() throws Exception {
         super.setUp();
 
-        mService = createActivityTaskManagerService();
-        mSupervisor = mService.mStackSupervisor;
+        setupActivityTaskManagerService();
         mFullscreenStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
     }
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
index 95f8fd1..ab814ee 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
@@ -60,8 +60,6 @@
 @Presubmit
 @RunWith(AndroidJUnit4.class)
 public class ActivityStackTests extends ActivityTestsBase {
-    private ActivityTaskManagerService mService;
-    private ActivityStackSupervisor mSupervisor;
     private ActivityDisplay mDefaultDisplay;
     private ActivityStack mStack;
     private TaskRecord mTask;
@@ -71,9 +69,8 @@
     public void setUp() throws Exception {
         super.setUp();
 
-        mService = createActivityTaskManagerService();
-        mSupervisor = mService.mStackSupervisor;
-        mDefaultDisplay = mService.mStackSupervisor.getDefaultDisplay();
+        setupActivityTaskManagerService();
+        mDefaultDisplay = mSupervisor.getDefaultDisplay();
         mStack = mDefaultDisplay.createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD,
                 true /* onTop */);
         mTask = new TaskBuilder(mSupervisor).setStack(mStack).build();
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java
index e1ebbcf..9192d6b 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java
@@ -83,7 +83,7 @@
         final WindowProcessController wpc = new WindowProcessController(mService,
                 mService.mContext.getApplicationInfo(), "name", 12345,
                 UserHandle.getUserId(12345), mock(Object.class),
-                mock(WindowProcessListener.class));
+                mock(WindowProcessListener.class), null);
         wpc.setThread(mock(IApplicationThread.class));
 
         mController.addPendingActivityLaunch(
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
index d032eb5..bac4a52 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
@@ -32,26 +32,32 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
+import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
 
+import static com.android.server.am.ActivityDisplay.POSITION_BOTTOM;
 import static com.android.server.am.ActivityManagerService.ANIMATE;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.anyObject;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyObject;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import android.app.ActivityOptions;
 import android.app.IApplicationThread;
+import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ActivityInfo.WindowLayout;
@@ -65,28 +71,6 @@
 import android.service.voice.IVoiceInteractionSession;
 import android.view.Gravity;
 
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
-import static com.android.server.am.ActivityManagerService.ANIMATE;
-import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.anyObject;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.times;
-
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
@@ -106,7 +90,6 @@
 @Presubmit
 @RunWith(AndroidJUnit4.class)
 public class ActivityStarterTests extends ActivityTestsBase {
-    private ActivityTaskManagerService mService;
     private ActivityStarter mStarter;
     private ActivityStartController mController;
     private ActivityMetricsLogger mActivityMetricsLogger;
@@ -130,7 +113,7 @@
     @Override
     public void setUp() throws Exception {
         super.setUp();
-        mService = createActivityTaskManagerService();
+        setupActivityTaskManagerService();
         mController = mock(ActivityStartController.class);
         mActivityMetricsLogger = mock(ActivityMetricsLogger.class);
         clearInvocations(mActivityMetricsLogger);
@@ -225,7 +208,7 @@
 
         // If no caller app, return {@code null} {@link ProcessRecord}.
         final ProcessRecord record = containsConditions(preconditions, PRECONDITION_NO_CALLER_APP)
-                ? null : new ProcessRecord(service.mAm, mock(ApplicationInfo.class), null, 0);
+                ? null : new ProcessRecord(service.mAm, mock(ApplicationInfo.class), null, 0, null);
 
         doReturn(record).when(service.mAm).getRecordForAppLocked(anyObject());
 
@@ -323,7 +306,22 @@
         }
     }
 
-    private ActivityStarter prepareStarter(int launchFlags) {
+    private ActivityStarter prepareStarter(@Intent.Flags int launchFlags) {
+        return prepareStarter(launchFlags, true /* mockGetLaunchStack */);
+    }
+
+    /**
+     * Creates a {@link ActivityStarter} with default parameters and necessary mocks.
+     *
+     * @param launchFlags The intent flags to launch activity.
+     * @param mockGetLaunchStack Whether to mock {@link ActivityStackSupervisor#getLaunchStack} for
+     *                           always launching to the testing stack. Set to false when allowing
+     *                           the activity can be launched to any stack that is decided by real
+     *                           implementation.
+     * @return A {@link ActivityStarter} with default setup.
+     */
+    private ActivityStarter prepareStarter(@Intent.Flags int launchFlags,
+            boolean mockGetLaunchStack) {
         // always allow test to start activity.
         doReturn(true).when(mService.mStackSupervisor).checkStartAnyActivityPermission(
                 any(), any(), any(), anyInt(), anyInt(), anyInt(), any(),
@@ -343,11 +341,13 @@
         // return task when created.
         doReturn(task).when(factory).create(any(), anyInt(), any(), any(), any(), any());
 
-        // direct starter to use spy stack.
-        doReturn(stack).when(mService.mStackSupervisor)
-                .getLaunchStack(any(), any(), any(), anyBoolean());
-        doReturn(stack).when(mService.mStackSupervisor)
-                .getLaunchStack(any(), any(), any(), anyBoolean(), anyInt());
+        if (mockGetLaunchStack) {
+            // Direct starter to use spy stack.
+            doReturn(stack).when(mService.mStackSupervisor)
+                    .getLaunchStack(any(), any(), any(), anyBoolean());
+            doReturn(stack).when(mService.mStackSupervisor)
+                    .getLaunchStack(any(), any(), any(), anyBoolean(), anyInt());
+        }
 
         // Set up mock package manager internal and make sure no unmocked methods are called
         PackageManagerInternal mockPackageManager = mock(PackageManagerInternal.class,
@@ -546,4 +546,84 @@
                 eq(ActivityBuilder.getDefaultComponent().getPackageName()), anyInt(), anyBoolean(),
                 any(), eq(false));
     }
+
+    /**
+     * This test ensures that when starting an existing single task activity on secondary display
+     * which is not the top focused display, it should deliver new intent to the activity and not
+     * create a new stack.
+     */
+    @Test
+    public void testDeliverIntentToTopActivityOfNonTopDisplay() {
+        final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
+                false /* mockGetLaunchStack */);
+
+        // Create a secondary display at bottom.
+        final TestActivityDisplay secondaryDisplay = spy(addNewActivityDisplayAt(POSITION_BOTTOM));
+        final ActivityStack stack = secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
+                ACTIVITY_TYPE_STANDARD, true /* onTop */);
+
+        // Create an activity record on the top of secondary display.
+        final ComponentName componentName = ComponentName.createRelative(
+                DEFAULT_COMPONENT_PACKAGE_NAME,
+                DEFAULT_COMPONENT_PACKAGE_NAME + ".ReusableActivity");
+        final TaskRecord taskRecord = new TaskBuilder(mSupervisor)
+                .setComponent(componentName)
+                .setStack(stack)
+                .build();
+        final ActivityRecord topActivityOnSecondaryDisplay = new ActivityBuilder(mService)
+                .setComponent(componentName)
+                .setLaunchMode(LAUNCH_SINGLE_TASK)
+                .setTask(taskRecord)
+                .build();
+
+        // Put an activity on default display as the top focused activity.
+        new ActivityBuilder(mService).setCreateTask(true).build();
+
+        // Start activity with the same intent as {@code topActivityOnSecondaryDisplay}
+        // on secondary display.
+        final ActivityOptions options = ActivityOptions.makeBasic()
+                .setLaunchDisplayId(secondaryDisplay.mDisplayId);
+        final int result = starter.setReason("testDeliverIntentToTopActivityOfNonTopDisplay")
+                .setIntent(topActivityOnSecondaryDisplay.intent)
+                .setActivityOptions(options.toBundle())
+                .execute();
+
+        // Ensure result is delivering intent to top.
+        assertEquals(START_DELIVERED_TO_TOP, result);
+
+        // Ensure secondary display only creates one stack.
+        verify(secondaryDisplay, times(1)).createStack(anyInt(), anyInt(), anyBoolean());
+    }
+
+    /**
+     * This test ensures that a reused top activity in the top focused stack is able to be
+     * reparented to another display.
+     */
+    @Test
+    public void testReparentTopFocusedActivityToSecondaryDisplay() {
+        final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
+                false /* mockGetLaunchStack */);
+
+        // Create a secondary display at bottom.
+        final TestActivityDisplay secondaryDisplay = addNewActivityDisplayAt(POSITION_BOTTOM);
+        secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
+                true /* onTop */);
+
+        // Put an activity on default display as the top focused activity.
+        final ActivityRecord topActivity = new ActivityBuilder(mService)
+                .setCreateTask(true)
+                .setLaunchMode(LAUNCH_SINGLE_TASK)
+                .build();
+
+        // Start activity with the same intent as {@code topActivity} on secondary display.
+        final ActivityOptions options = ActivityOptions.makeBasic()
+                .setLaunchDisplayId(secondaryDisplay.mDisplayId);
+        starter.setReason("testReparentTopFocusedActivityToSecondaryDisplay")
+                .setIntent(topActivity.intent)
+                .setActivityOptions(options.toBundle())
+                .execute();
+
+        // Ensure the activity is moved to secondary display.
+        assertEquals(secondaryDisplay, topActivity.getDisplay());
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index bb8e5c5..22add01 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -22,6 +22,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
 
 import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
 import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
@@ -56,11 +57,14 @@
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerGlobal;
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.UserHandle;
 import android.service.voice.IVoiceInteractionSession;
 import android.testing.DexmakerShareClassLoaderRule;
+import android.view.Display;
+import android.view.DisplayInfo;
 
 import androidx.test.InstrumentationRegistry;
 
@@ -86,6 +90,8 @@
 public class ActivityTestsBase {
     private static boolean sOneTimeSetupDone = false;
 
+    private static int sNextDisplayId = DEFAULT_DISPLAY + 1;
+
     @Rule
     public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
             new DexmakerShareClassLoaderRule();
@@ -93,6 +99,9 @@
     private final Context mContext = InstrumentationRegistry.getContext();
     private HandlerThread mHandlerThread;
 
+    ActivityTaskManagerService mService;
+    ActivityStackSupervisor mSupervisor;
+
     // Default package name
     static final String DEFAULT_COMPONENT_PACKAGE_NAME = "com.foo";
 
@@ -122,6 +131,11 @@
         return atm;
     }
 
+    void setupActivityTaskManagerService() {
+        mService = createActivityTaskManagerService();
+        mSupervisor = mService.mStackSupervisor;
+    }
+
     ActivityManagerService createActivityManagerService() {
         final TestActivityTaskManagerService atm =
                 spy(new TestActivityTaskManagerService(mContext));
@@ -134,6 +148,18 @@
         return am;
     }
 
+    /** Creates a {@link TestActivityDisplay}. */
+    TestActivityDisplay createNewActivityDisplay() {
+        return TestActivityDisplay.create(mSupervisor, sNextDisplayId++);
+    }
+
+    /** Creates and adds a {@link TestActivityDisplay} to supervisor at the given position. */
+    TestActivityDisplay addNewActivityDisplayAt(int position) {
+        final TestActivityDisplay display = createNewActivityDisplay();
+        mSupervisor.addChild(display, position);
+        return display;
+    }
+
     void setupActivityManagerService(
             TestActivityManagerService am, TestActivityTaskManagerService atm) {
         atm.setActivityManagerService(am);
@@ -173,6 +199,7 @@
         private boolean mCreateTask;
         private ActivityStack mStack;
         private int mActivityFlags;
+        private int mLaunchMode;
 
         ActivityBuilder(ActivityTaskManagerService service) {
             mService = service;
@@ -198,6 +225,11 @@
             return this;
         }
 
+        ActivityBuilder setLaunchMode(int launchMode) {
+            mLaunchMode = launchMode;
+            return this;
+        }
+
         ActivityBuilder setStack(ActivityStack stack) {
             mStack = stack;
             return this;
@@ -233,6 +265,7 @@
             aInfo.applicationInfo.packageName = mComponent.getPackageName();
             aInfo.applicationInfo.uid = mUid;
             aInfo.flags |= mActivityFlags;
+            aInfo.launchMode = mLaunchMode;
 
             final ActivityRecord activity = new ActivityRecord(mService, null /* caller */,
                     0 /* launchedFromPid */, 0, null, intent, null,
@@ -248,7 +281,7 @@
             final WindowProcessController wpc = new WindowProcessController(mService,
                     mService.mContext.getApplicationInfo(), "name", 12345,
                     UserHandle.getUserId(12345), mock(Object.class),
-                    mock(WindowProcessListener.class));
+                    mock(WindowProcessListener.class), null);
             wpc.setThread(mock(IApplicationThread.class));
             activity.setProcess(wpc);
             return activity;
@@ -406,6 +439,10 @@
         }
 
         @Override
+        void updateUsageStats(ActivityRecord component, boolean resumed) {
+        }
+
+        @Override
         final protected ActivityStackSupervisor createStackSupervisor() {
             final ActivityStackSupervisor supervisor = spy(createTestSupervisor());
             final KeyguardController keyguardController = mock(KeyguardController.class);
@@ -464,10 +501,6 @@
         }
 
         @Override
-        void updateUsageStats(ActivityRecord component, boolean resumed) {
-        }
-
-        @Override
         Configuration getGlobalConfiguration() {
             return mContext.getResources().getConfiguration();
         }
@@ -500,7 +533,7 @@
         @Override
         public void initialize() {
             super.initialize();
-            mDisplay = spy(new TestActivityDisplay(this, DEFAULT_DISPLAY));
+            mDisplay = spy(TestActivityDisplay.create(this, DEFAULT_DISPLAY));
             addChild(mDisplay, ActivityDisplay.POSITION_TOP);
         }
 
@@ -516,10 +549,20 @@
     }
 
     protected static class TestActivityDisplay extends ActivityDisplay {
-
         private final ActivityStackSupervisor mSupervisor;
-        TestActivityDisplay(ActivityStackSupervisor supervisor, int displayId) {
-            super(supervisor, displayId);
+
+        static TestActivityDisplay create(ActivityStackSupervisor supervisor, int displayId) {
+            if (displayId == DEFAULT_DISPLAY) {
+                return new TestActivityDisplay(supervisor,
+                        supervisor.mDisplayManager.getDisplay(displayId));
+            }
+            final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
+                    new DisplayInfo(), DEFAULT_DISPLAY_ADJUSTMENTS);
+            return new TestActivityDisplay(supervisor, display);
+        }
+
+        TestActivityDisplay(ActivityStackSupervisor supervisor, Display display) {
+            super(supervisor, display);
             // Normally this comes from display-properties as exposed by WM. Without that, just
             // hard-code to FULLSCREEN for tests.
             setWindowingMode(WINDOWING_MODE_FULLSCREEN);
diff --git a/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
index 87d367f..3819e21 100644
--- a/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
@@ -67,7 +67,7 @@
     @UiThreadTest
     public void testCreateWorks() throws Exception {
         AppErrorDialog.Data data = new AppErrorDialog.Data();
-        data.proc = new ProcessRecord(null, mContext.getApplicationInfo(), "name", 12345);
+        data.proc = new ProcessRecord(null, mContext.getApplicationInfo(), "name", 12345, null);
         data.result = new AppErrorResult();
 
         AppErrorDialog dialog = new AppErrorDialog(mContext, mService, data);
diff --git a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
index 06c7437..e8a824a 100644
--- a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
@@ -16,9 +16,12 @@
 
 package com.android.server.am;
 
+import static com.android.server.am.MemoryStatUtil.BYTES_IN_KILOBYTE;
 import static com.android.server.am.MemoryStatUtil.MemoryStat;
+import static com.android.server.am.MemoryStatUtil.parseMemoryMaxUsageFromMemCg;
 import static com.android.server.am.MemoryStatUtil.parseMemoryStatFromMemcg;
 import static com.android.server.am.MemoryStatUtil.parseMemoryStatFromProcfs;
+import static com.android.server.am.MemoryStatUtil.parseVmHWMFromProcfs;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
@@ -32,7 +35,7 @@
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class MemoryStatUtilTest {
-    private String MEMORY_STAT_CONTENTS = String.join(
+    private static final String MEMORY_STAT_CONTENTS = String.join(
             "\n",
             "cache 96", // keep different from total_cache to catch reading wrong value
             "rss 97", // keep different from total_rss to catch reading wrong value
@@ -67,7 +70,7 @@
             "total_active_file 81920",
             "total_unevictable 0");
 
-    private String PROC_STAT_CONTENTS = String.join(
+    private static final String PROC_STAT_CONTENTS = String.join(
             " ",
             "1040",
             "(system_server)",
@@ -122,14 +125,61 @@
             "3198889956",
             "0");
 
+    private static final String PROC_STATUS_CONTENTS = "Name:\tandroid.youtube\n"
+        + "State:\tS (sleeping)\n"
+        + "Tgid:\t12088\n"
+        + "Pid:\t12088\n"
+        + "PPid:\t723\n"
+        + "TracerPid:\t0\n"
+        + "Uid:\t10083\t10083\t10083\t10083\n"
+        + "Gid:\t10083\t10083\t10083\t10083\n"
+        + "Ngid:\t0\n"
+        + "FDSize:\t128\n"
+        + "Groups:\t3003 9997 20083 50083 \n"
+        + "VmPeak:\t 4546844 kB\n"
+        + "VmSize:\t 4542636 kB\n"
+        + "VmLck:\t       0 kB\n"
+        + "VmPin:\t       0 kB\n"
+        + "VmHWM:\t  137668 kB\n" // RSS high watermark
+        + "VmRSS:\t  126776 kB\n"
+        + "RssAnon:\t   37860 kB\n"
+        + "RssFile:\t   88764 kB\n"
+        + "RssShmem:\t     152 kB\n"
+        + "VmData:\t 4125112 kB\n"
+        + "VmStk:\t    8192 kB\n"
+        + "VmExe:\t      24 kB\n"
+        + "VmLib:\t  102432 kB\n"
+        + "VmPTE:\t    1300 kB\n"
+        + "VmPMD:\t      36 kB\n"
+        + "VmSwap:\t       0 kB\n"
+        + "Threads:\t95\n"
+        + "SigQ:\t0/13641\n"
+        + "SigPnd:\t0000000000000000\n"
+        + "ShdPnd:\t0000000000000000\n"
+        + "SigBlk:\t0000000000001204\n"
+        + "SigIgn:\t0000000000000001\n"
+        + "SigCgt:\t00000006400084f8\n"
+        + "CapInh:\t0000000000000000\n"
+        + "CapPrm:\t0000000000000000\n"
+        + "CapEff:\t0000000000000000\n"
+        + "CapBnd:\t0000000000000000\n"
+        + "CapAmb:\t0000000000000000\n"
+        + "Seccomp:\t2\n"
+        + "Cpus_allowed:\tff\n"
+        + "Cpus_allowed_list:\t0-7\n"
+        + "Mems_allowed:\t1\n"
+        + "Mems_allowed_list:\t0\n"
+        + "voluntary_ctxt_switches:\t903\n"
+        + "nonvoluntary_ctxt_switches:\t104\n";
+
     @Test
     public void testParseMemoryStatFromMemcg_parsesCorrectValues() throws Exception {
         MemoryStat stat = parseMemoryStatFromMemcg(MEMORY_STAT_CONTENTS);
-        assertEquals(stat.pgfault, 1);
-        assertEquals(stat.pgmajfault, 2);
-        assertEquals(stat.rssInBytes, 3);
-        assertEquals(stat.cacheInBytes, 4);
-        assertEquals(stat.swapInBytes, 5);
+        assertEquals(1, stat.pgfault);
+        assertEquals(2, stat.pgmajfault);
+        assertEquals(3, stat.rssInBytes);
+        assertEquals(4, stat.cacheInBytes);
+        assertEquals(5, stat.swapInBytes);
     }
 
     @Test
@@ -142,6 +192,18 @@
     }
 
     @Test
+    public void testParseMemoryMaxUsageFromMemCg_parsesCorrectValue() {
+        assertEquals(1234, parseMemoryMaxUsageFromMemCg("1234"));
+    }
+
+    @Test
+    public void testParseMemoryMaxUsageFromMemCg_emptyContents() {
+        assertEquals(0, parseMemoryMaxUsageFromMemCg(""));
+
+        assertEquals(0, parseMemoryMaxUsageFromMemCg(null));
+    }
+
+    @Test
     public void testParseMemoryStatFromProcfs_parsesCorrectValues() throws Exception {
         MemoryStat stat = parseMemoryStatFromProcfs(PROC_STAT_CONTENTS);
         assertEquals(1, stat.pgfault);
@@ -159,4 +221,16 @@
         stat = parseMemoryStatFromProcfs(null);
         assertNull(stat);
     }
+
+    @Test
+    public void testParseVmHWMFromProcfs_parsesCorrectValue() {
+        assertEquals(137668, parseVmHWMFromProcfs(PROC_STATUS_CONTENTS) / BYTES_IN_KILOBYTE);
+    }
+
+    @Test
+    public void testParseVmHWMFromProcfs_emptyContents() {
+        assertEquals(0, parseVmHWMFromProcfs(""));
+
+        assertEquals(0, parseVmHWMFromProcfs(null));
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
index 5195214..70cfad1 100644
--- a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
@@ -870,8 +870,8 @@
         @Override
         public void initialize() {
             super.initialize();
-            mDisplay = new TestActivityDisplay(this, DEFAULT_DISPLAY);
-            mOtherDisplay = new TestActivityDisplay(this, DEFAULT_DISPLAY);
+            mDisplay = TestActivityDisplay.create(this, DEFAULT_DISPLAY);
+            mOtherDisplay = TestActivityDisplay.create(this, DEFAULT_DISPLAY + 1);
             addChild(mOtherDisplay, ActivityDisplay.POSITION_TOP);
             addChild(mDisplay, ActivityDisplay.POSITION_TOP);
         }
diff --git a/services/tests/servicestests/src/com/android/server/am/RunningTasksTest.java b/services/tests/servicestests/src/com/android/server/am/RunningTasksTest.java
index d56c6a6..aa3046f 100644
--- a/services/tests/servicestests/src/com/android/server/am/RunningTasksTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/RunningTasksTest.java
@@ -51,7 +51,6 @@
 public class RunningTasksTest extends ActivityTestsBase {
 
     private Context mContext = InstrumentationRegistry.getContext();
-    private ActivityTaskManagerService mService;
 
     private RunningTasks mRunningTasks;
 
@@ -60,21 +59,20 @@
     public void setUp() throws Exception {
         super.setUp();
 
-        mService = createActivityTaskManagerService();
+        setupActivityTaskManagerService();
         mRunningTasks = new RunningTasks();
     }
 
     @Test
     public void testCollectTasksByLastActiveTime() throws Exception {
         // Create a number of stacks with tasks (of incrementing active time)
-        final ActivityStackSupervisor supervisor = mService.mStackSupervisor;
         final ArrayList<ActivityDisplay> displays = new ArrayList<>();
-        final ActivityDisplay display = new TestActivityDisplay(supervisor, DEFAULT_DISPLAY);
+        final ActivityDisplay display = TestActivityDisplay.create(mSupervisor, DEFAULT_DISPLAY);
         displays.add(display);
 
         final int numStacks = 2;
         for (int stackIndex = 0; stackIndex < numStacks; stackIndex++) {
-            final ActivityStack stack = new TestActivityStack(display, stackIndex, supervisor,
+            final ActivityStack stack = new TestActivityStack(display, stackIndex, mSupervisor,
                     WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true);
             display.addChild(stack, POSITION_BOTTOM);
         }
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
similarity index 97%
rename from core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
rename to services/tests/servicestests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
index 8a83518..910d433 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.inputmethod;
+package com.android.server.inputmethod;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -23,15 +23,15 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodSubtype;
 import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
 
-import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ControllerImpl;
-import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
-import com.android.internal.inputmethod.InputMethodUtils;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ControllerImpl;
+import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java
similarity index 90%
rename from core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
rename to services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java
index 3064afa..4d0278f 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.inputmethod;
+package com.android.server.inputmethod;
 
 import static android.view.inputmethod.InputMethodManager.CONTROL_WINDOW_IS_TEXT_EDITOR;
 import static android.view.inputmethod.InputMethodManager.CONTROL_WINDOW_VIEW_HAS_FOCUS;
@@ -37,13 +37,14 @@
 import android.os.Build;
 import android.os.LocaleList;
 import android.os.Parcel;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodSubtype;
 import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -71,15 +72,11 @@
     private static final Locale LOCALE_FR = new Locale("fr");
     private static final Locale LOCALE_FR_CA = new Locale("fr", "CA");
     private static final Locale LOCALE_HI = new Locale("hi");
-    private static final Locale LOCALE_JA = new Locale("ja");
     private static final Locale LOCALE_JA_JP = new Locale("ja", "JP");
     private static final Locale LOCALE_ZH_CN = new Locale("zh", "CN");
     private static final Locale LOCALE_ZH_TW = new Locale("zh", "TW");
     private static final Locale LOCALE_IN = new Locale("in");
     private static final Locale LOCALE_ID = new Locale("id");
-    private static final Locale LOCALE_TH = new Locale("ht");
-    private static final Locale LOCALE_TH_TH = new Locale("ht", "TH");
-    private static final Locale LOCALE_TH_TH_TH = new Locale("ht", "TH", "TH");
     private static final String SUBTYPE_MODE_KEYBOARD = "keyboard";
     private static final String SUBTYPE_MODE_VOICE = "voice";
     private static final String SUBTYPE_MODE_HANDWRITING = "handwriting";
@@ -1087,122 +1084,6 @@
     }
 
     @Test
-    public void testGetSuitableLocalesForSpellChecker() throws Exception {
-        {
-            final ArrayList<Locale> locales =
-                    InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_US);
-            assertEquals(3, locales.size());
-            assertEquals(LOCALE_EN_US, locales.get(0));
-            assertEquals(LOCALE_EN_GB, locales.get(1));
-            assertEquals(LOCALE_EN, locales.get(2));
-        }
-
-        {
-            final ArrayList<Locale> locales =
-                    InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_GB);
-            assertEquals(3, locales.size());
-            assertEquals(LOCALE_EN_GB, locales.get(0));
-            assertEquals(LOCALE_EN_US, locales.get(1));
-            assertEquals(LOCALE_EN, locales.get(2));
-        }
-
-        {
-            final ArrayList<Locale> locales =
-                    InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN);
-            assertEquals(3, locales.size());
-            assertEquals(LOCALE_EN, locales.get(0));
-            assertEquals(LOCALE_EN_US, locales.get(1));
-            assertEquals(LOCALE_EN_GB, locales.get(2));
-        }
-
-        {
-            final ArrayList<Locale> locales =
-                    InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_IN);
-            assertEquals(4, locales.size());
-            assertEquals(LOCALE_EN_IN, locales.get(0));
-            assertEquals(LOCALE_EN_US, locales.get(1));
-            assertEquals(LOCALE_EN_GB, locales.get(2));
-            assertEquals(LOCALE_EN, locales.get(3));
-        }
-
-        {
-            final ArrayList<Locale> locales =
-                    InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_JA_JP);
-            assertEquals(5, locales.size());
-            assertEquals(LOCALE_JA_JP, locales.get(0));
-            assertEquals(LOCALE_JA, locales.get(1));
-            assertEquals(LOCALE_EN_US, locales.get(2));
-            assertEquals(LOCALE_EN_GB, locales.get(3));
-            assertEquals(Locale.ENGLISH, locales.get(4));
-        }
-
-        // Test 3-letter language code.
-        {
-            final ArrayList<Locale> locales =
-                    InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_FIL_PH);
-            assertEquals(5, locales.size());
-            assertEquals(LOCALE_FIL_PH, locales.get(0));
-            assertEquals(LOCALE_FIL, locales.get(1));
-            assertEquals(LOCALE_EN_US, locales.get(2));
-            assertEquals(LOCALE_EN_GB, locales.get(3));
-            assertEquals(Locale.ENGLISH, locales.get(4));
-        }
-
-        // Test variant.
-        {
-            final ArrayList<Locale> locales =
-                    InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_TH_TH_TH);
-            assertEquals(6, locales.size());
-            assertEquals(LOCALE_TH_TH_TH, locales.get(0));
-            assertEquals(LOCALE_TH_TH, locales.get(1));
-            assertEquals(LOCALE_TH, locales.get(2));
-            assertEquals(LOCALE_EN_US, locales.get(3));
-            assertEquals(LOCALE_EN_GB, locales.get(4));
-            assertEquals(Locale.ENGLISH, locales.get(5));
-        }
-
-        // Test Locale extension.
-        {
-            final Locale localeWithoutVariant = LOCALE_JA_JP;
-            final Locale localeWithVariant = new Locale.Builder()
-                    .setLocale(LOCALE_JA_JP)
-                    .setExtension('x', "android")
-                    .build();
-            assertFalse(localeWithoutVariant.equals(localeWithVariant));
-
-            final ArrayList<Locale> locales =
-                    InputMethodUtils.getSuitableLocalesForSpellChecker(localeWithVariant);
-            assertEquals(5, locales.size());
-            assertEquals(LOCALE_JA_JP, locales.get(0));
-            assertEquals(LOCALE_JA, locales.get(1));
-            assertEquals(LOCALE_EN_US, locales.get(2));
-            assertEquals(LOCALE_EN_GB, locales.get(3));
-            assertEquals(Locale.ENGLISH, locales.get(4));
-        }
-    }
-
-    @Test
-    public void testConstructLocaleFromString() throws Exception {
-        assertEquals(new Locale("en"), InputMethodUtils.constructLocaleFromString("en"));
-        assertEquals(new Locale("en", "US"), InputMethodUtils.constructLocaleFromString("en_US"));
-        assertEquals(new Locale("en", "US", "POSIX"),
-                InputMethodUtils.constructLocaleFromString("en_US_POSIX"));
-
-        // Special rewrite rule for "tl" for versions of Android earlier than Lollipop that did not
-        // support three letter language codes, and used "tl" (Tagalog) as the language string for
-        // "fil" (Filipino).
-        assertEquals(new Locale("fil"), InputMethodUtils.constructLocaleFromString("tl"));
-        assertEquals(new Locale("fil", "PH"), InputMethodUtils.constructLocaleFromString("tl_PH"));
-        assertEquals(new Locale("fil", "PH", "POSIX"),
-                InputMethodUtils.constructLocaleFromString("tl_PH_POSIX"));
-
-        // So far rejecting an invalid/unexpected locale string is out of the scope of this method.
-        assertEquals(new Locale("a"), InputMethodUtils.constructLocaleFromString("a"));
-        assertEquals(new Locale("a b c"), InputMethodUtils.constructLocaleFromString("a b c"));
-        assertEquals(new Locale("en-US"), InputMethodUtils.constructLocaleFromString("en-US"));
-    }
-
-    @Test
     public void testIsSoftInputModeStateVisibleAllowed() {
         // On pre-P devices, SOFT_INPUT_STATE_VISIBLE/SOFT_INPUT_STATE_ALWAYS_VISIBLE are always
         // allowed, regardless of the focused view state.
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java b/services/tests/servicestests/src/com/android/server/inputmethod/LocaleUtilsTest.java
similarity index 98%
rename from core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java
rename to services/tests/servicestests/src/com/android/server/inputmethod/LocaleUtilsTest.java
index 549511a..3fc0e4f 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/inputmethod/LocaleUtilsTest.java
@@ -14,13 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.internal.inputmethod;
+package com.android.server.inputmethod;
 
 import static org.junit.Assert.assertEquals;
 
 import android.os.LocaleList;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index ee41c0b..c3c0788 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -716,9 +716,9 @@
         assertNotSame(origPkgSetting.mPermissionsState, testPkgSetting.mPermissionsState);
         assertThat(origPkgSetting.mPermissionsState, is(testPkgSetting.mPermissionsState));
         assertThat(origPkgSetting.name, is(testPkgSetting.name));
-        // oldCodePaths is _not_ copied
-        // assertNotSame(origPkgSetting.oldCodePaths, testPkgSetting.oldCodePaths);
-        // assertThat(origPkgSetting.oldCodePaths, is(not(testPkgSetting.oldCodePaths)));
+        // mOldCodePaths is _not_ copied
+        // assertNotSame(origPkgSetting.mOldCodePaths, testPkgSetting.mOldCodePaths);
+        // assertThat(origPkgSetting.mOldCodePaths, is(not(testPkgSetting.mOldCodePaths)));
         assertSame(origPkgSetting.parentPackageName, testPkgSetting.parentPackageName);
         assertThat(origPkgSetting.parentPackageName, is(testPkgSetting.parentPackageName));
         assertSame(origPkgSetting.pkg, testPkgSetting.pkg);
diff --git a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
index b238e43..d34f951 100644
--- a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
+++ b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
@@ -30,7 +30,7 @@
 
 public class FakeWindowState implements WindowManagerPolicy.WindowState {
 
-    private WindowFrames windowFrames;
+    private WindowFrames mWindowFrames = new WindowFrames();
 
     public WindowManager.LayoutParams attrs;
     public int displayId;
@@ -53,41 +53,40 @@
     }
 
     @Override
-    public void computeFrameLw(WindowFrames windowFrames) {
-        this.windowFrames = windowFrames;
+    public void computeFrameLw() {
     }
 
     @Override
     public Rect getFrameLw() {
-        return windowFrames.mParentFrame;
+        return mWindowFrames.mParentFrame;
     }
 
     @Override
     public Rect getDisplayFrameLw() {
-        return windowFrames.mDisplayFrame;
+        return mWindowFrames.mDisplayFrame;
     }
 
     @Override
     public Rect getOverscanFrameLw() {
-        return windowFrames.mOverscanFrame;
+        return mWindowFrames.mOverscanFrame;
     }
 
     @Override
     public Rect getContentFrameLw() {
-        return windowFrames.mContentFrame;
+        return mWindowFrames.mContentFrame;
     }
 
     @Override
     public Rect getVisibleFrameLw() {
-        return windowFrames.mVisibleFrame;
+        return mWindowFrames.mVisibleFrame;
     }
 
     public Rect getStableFrame() {
-        return windowFrames.mStableFrame;
+        return mWindowFrames.mStableFrame;
     }
 
     public Rect getDecorFrame() {
-        return windowFrames.mDecorFrame;
+        return mWindowFrames.mDecorFrame;
     }
 
     @Override
@@ -252,6 +251,11 @@
     }
 
     @Override
+    public WindowFrames getWindowFrames() {
+        return mWindowFrames;
+    }
+
+    @Override
     public boolean isInputMethodTarget() {
         return false;
     }
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 5039e42..8ac2930 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -21,18 +21,32 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Matchers.eq;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import android.app.ActivityManagerInternal;
+import android.content.Context;
+import android.hardware.display.DisplayManagerInternal;
 import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
+import android.os.BatteryManagerInternal;
+import android.os.Looper;
 import android.os.PowerManager;
 import android.os.PowerSaveState;
+import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
-import com.android.server.power.batterysaver.BatterySaverController;
+import com.android.internal.app.IBatteryStats;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+import com.android.server.lights.LightsManager;
+import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.power.PowerManagerService.Injector;
+import com.android.server.power.PowerManagerService.NativeWrapper;
+import com.android.server.power.batterysaver.BatterySavingStats;
 
 import org.junit.Rule;
 import org.mockito.Mock;
@@ -47,11 +61,19 @@
     private static final boolean BATTERY_SAVER_ENABLED = true;
     private static final String TEST_LAST_REBOOT_PROPERTY = "test.sys.boot.reason";
 
-    private @Mock BatterySaverPolicy mBatterySaverPolicy;
+    private @Mock BatterySaverPolicy mBatterySaverPolicyMock;
+    private @Mock LightsManager mLightsManagerMock;
+    private @Mock DisplayManagerInternal mDisplayManagerInternalMock;
+    private @Mock BatteryManagerInternal mBatteryManagerInternalMock;
+    private @Mock ActivityManagerInternal mActivityManagerInternalMock;
+    private @Mock PowerManagerService.NativeWrapper mNativeWrapperMock;
+    private @Mock Notifier mNotifierMock;
     private PowerManagerService mService;
     private PowerSaveState mPowerSaveState;
     private DisplayPowerRequest mDisplayPowerRequest;
 
+
+
     @Rule
     public void setUp() throws Exception {
         super.setUp();
@@ -61,11 +83,51 @@
                 .setBatterySaverEnabled(BATTERY_SAVER_ENABLED)
                 .setBrightnessFactor(BRIGHTNESS_FACTOR)
                 .build();
-        when(mBatterySaverPolicy.getBatterySaverPolicy(
+        when(mBatterySaverPolicyMock.getBatterySaverPolicy(
                 eq(PowerManager.ServiceType.SCREEN_BRIGHTNESS), anyBoolean()))
                 .thenReturn(mPowerSaveState);
+
         mDisplayPowerRequest = new DisplayPowerRequest();
-        mService = new PowerManagerService(getContext(), mBatterySaverPolicy);
+        addLocalServiceMock(LightsManager.class, mLightsManagerMock);
+        addLocalServiceMock(DisplayManagerInternal.class, mDisplayManagerInternalMock);
+        addLocalServiceMock(BatteryManagerInternal.class, mBatteryManagerInternalMock);
+        addLocalServiceMock(ActivityManagerInternal.class, mActivityManagerInternalMock);
+
+        mService = new PowerManagerService(getContext(), new Injector() {
+            Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
+                    SuspendBlocker suspendBlocker, WindowManagerPolicy policy) {
+                return mNotifierMock;
+            }
+
+            SuspendBlocker createSuspendBlocker(PowerManagerService service, String name) {
+                return mock(SuspendBlocker.class);
+            }
+
+            BatterySaverPolicy createBatterySaverPolicy(
+                    Object lock, Context context, BatterySavingStats batterySavingStats) {
+                return mBatterySaverPolicyMock;
+            }
+
+            NativeWrapper createNativeWrapper() {
+                return mNativeWrapperMock;
+            }
+        });
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        LocalServices.removeServiceForTest(LightsManager.class);
+        LocalServices.removeServiceForTest(DisplayManagerInternal.class);
+        LocalServices.removeServiceForTest(BatteryManagerInternal.class);
+        LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+    }
+
+    /**
+     * Creates a mock and registers it to {@link LocalServices}.
+     */
+    private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
+        LocalServices.removeServiceForTest(clazz);
+        LocalServices.addService(clazz, mock);
     }
 
     @SmallTest
@@ -110,6 +172,25 @@
         mService.setVrModeEnabled(false);
         assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
                 DisplayPowerRequest.POLICY_BRIGHT);
+    }
 
+    @SmallTest
+    public void testWakefulnessAwake_InitialValue() throws Exception {
+        assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE);
+    }
+
+    @SmallTest
+    public void testWakefulnessSleep_NoDozeSleepFlag() throws Exception {
+        // Start with AWAKE state
+        assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE);
+
+        mService.systemReady(null);
+        mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
+
+        // Take a nap with a flag.
+        mService.getBinderServiceInstance().goToSleep(SystemClock.uptimeMillis(),
+            PowerManager.GO_TO_SLEEP_REASON_APPLICATION, PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
+
+        assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP);
     }
 }
diff --git a/core/tests/coretests/src/com/android/internal/textservice/LazyIntToIntMapTest.java b/services/tests/servicestests/src/com/android/server/textservices/LazyIntToIntMapTest.java
similarity index 95%
rename from core/tests/coretests/src/com/android/internal/textservice/LazyIntToIntMapTest.java
rename to services/tests/servicestests/src/com/android/server/textservices/LazyIntToIntMapTest.java
index 3518527..f80afb2 100644
--- a/core/tests/coretests/src/com/android/internal/textservice/LazyIntToIntMapTest.java
+++ b/services/tests/servicestests/src/com/android/server/textservices/LazyIntToIntMapTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.textservice;
+package com.android.server.textservices;
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -25,8 +25,8 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/textservices/LocaleUtilsTest.java b/services/tests/servicestests/src/com/android/server/textservices/LocaleUtilsTest.java
new file mode 100644
index 0000000..3766d24
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/textservices/LocaleUtilsTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.textservices;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Locale;
+
+public class LocaleUtilsTest {
+    private static final Locale LOCALE_EN = new Locale("en");
+    private static final Locale LOCALE_EN_US = new Locale("en", "US");
+    private static final Locale LOCALE_EN_GB = new Locale("en", "GB");
+    private static final Locale LOCALE_EN_IN = new Locale("en", "IN");
+    private static final Locale LOCALE_FIL = new Locale("fil");
+    private static final Locale LOCALE_FIL_PH = new Locale("fil", "PH");
+    private static final Locale LOCALE_JA = new Locale("ja");
+    private static final Locale LOCALE_JA_JP = new Locale("ja", "JP");
+    private static final Locale LOCALE_TH = new Locale("ht");
+    private static final Locale LOCALE_TH_TH = new Locale("ht", "TH");
+    private static final Locale LOCALE_TH_TH_TH = new Locale("ht", "TH", "TH");
+
+    @Test
+    public void testGetSuitableLocalesForSpellChecker() throws Exception {
+        {
+            final ArrayList<Locale> locales =
+                    LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_US);
+            assertEquals(3, locales.size());
+            assertEquals(LOCALE_EN_US, locales.get(0));
+            assertEquals(LOCALE_EN_GB, locales.get(1));
+            assertEquals(LOCALE_EN, locales.get(2));
+        }
+
+        {
+            final ArrayList<Locale> locales =
+                    LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_GB);
+            assertEquals(3, locales.size());
+            assertEquals(LOCALE_EN_GB, locales.get(0));
+            assertEquals(LOCALE_EN_US, locales.get(1));
+            assertEquals(LOCALE_EN, locales.get(2));
+        }
+
+        {
+            final ArrayList<Locale> locales =
+                    LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_EN);
+            assertEquals(3, locales.size());
+            assertEquals(LOCALE_EN, locales.get(0));
+            assertEquals(LOCALE_EN_US, locales.get(1));
+            assertEquals(LOCALE_EN_GB, locales.get(2));
+        }
+
+        {
+            final ArrayList<Locale> locales =
+                    LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_IN);
+            assertEquals(4, locales.size());
+            assertEquals(LOCALE_EN_IN, locales.get(0));
+            assertEquals(LOCALE_EN_US, locales.get(1));
+            assertEquals(LOCALE_EN_GB, locales.get(2));
+            assertEquals(LOCALE_EN, locales.get(3));
+        }
+
+        {
+            final ArrayList<Locale> locales =
+                    LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_JA_JP);
+            assertEquals(5, locales.size());
+            assertEquals(LOCALE_JA_JP, locales.get(0));
+            assertEquals(LOCALE_JA, locales.get(1));
+            assertEquals(LOCALE_EN_US, locales.get(2));
+            assertEquals(LOCALE_EN_GB, locales.get(3));
+            assertEquals(Locale.ENGLISH, locales.get(4));
+        }
+
+        // Test 3-letter language code.
+        {
+            final ArrayList<Locale> locales =
+                    LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_FIL_PH);
+            assertEquals(5, locales.size());
+            assertEquals(LOCALE_FIL_PH, locales.get(0));
+            assertEquals(LOCALE_FIL, locales.get(1));
+            assertEquals(LOCALE_EN_US, locales.get(2));
+            assertEquals(LOCALE_EN_GB, locales.get(3));
+            assertEquals(Locale.ENGLISH, locales.get(4));
+        }
+
+        // Test variant.
+        {
+            final ArrayList<Locale> locales =
+                    LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_TH_TH_TH);
+            assertEquals(6, locales.size());
+            assertEquals(LOCALE_TH_TH_TH, locales.get(0));
+            assertEquals(LOCALE_TH_TH, locales.get(1));
+            assertEquals(LOCALE_TH, locales.get(2));
+            assertEquals(LOCALE_EN_US, locales.get(3));
+            assertEquals(LOCALE_EN_GB, locales.get(4));
+            assertEquals(Locale.ENGLISH, locales.get(5));
+        }
+
+        // Test Locale extension.
+        {
+            final Locale localeWithoutVariant = LOCALE_JA_JP;
+            final Locale localeWithVariant = new Locale.Builder()
+                    .setLocale(LOCALE_JA_JP)
+                    .setExtension('x', "android")
+                    .build();
+            assertFalse(localeWithoutVariant.equals(localeWithVariant));
+
+            final ArrayList<Locale> locales =
+                    LocaleUtils.getSuitableLocalesForSpellChecker(localeWithVariant);
+            assertEquals(5, locales.size());
+            assertEquals(LOCALE_JA_JP, locales.get(0));
+            assertEquals(LOCALE_JA, locales.get(1));
+            assertEquals(LOCALE_EN_US, locales.get(2));
+            assertEquals(LOCALE_EN_GB, locales.get(3));
+            assertEquals(Locale.ENGLISH, locales.get(4));
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index e7c45d5..aaa00452 100644
--- a/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.view.Display.DEFAULT_DISPLAY;
@@ -24,6 +25,8 @@
 import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
 
 import static org.junit.Assert.fail;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.verify;
@@ -33,6 +36,7 @@
 import android.os.Binder;
 import android.os.IInterface;
 import android.platform.test.annotations.Presubmit;
+import android.util.SparseBooleanArray;
 import android.view.IRecentsAnimationRunner;
 import android.view.SurfaceControl;
 
@@ -109,6 +113,24 @@
         }
     }
 
+    @Test
+    public void testIncludedApps_expectTargetAndVisible() throws Exception {
+        sWm.setRecentsAnimationController(mController);
+        final AppWindowToken homeAppWindow = createAppWindowToken(mDisplayContent,
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
+        final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+        final AppWindowToken hiddenAppWindow = createAppWindowToken(mDisplayContent,
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+        hiddenAppWindow.setHidden(true);
+        mController.initialize(mDisplayContent, ACTIVITY_TYPE_HOME, new SparseBooleanArray());
+
+        // Ensure that we are animating the target activity as well
+        assertTrue(mController.isAnimatingTask(homeAppWindow.getTask()));
+        assertTrue(mController.isAnimatingTask(appWindow.getTask()));
+        assertFalse(mController.isAnimatingTask(hiddenAppWindow.getTask()));
+    }
+
     private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) {
         verify(binder, atLeast(0)).asBinder();
         verifyNoMoreInteractions(binder);
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
index 9fa5ba4..ea44279 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
@@ -109,4 +109,22 @@
         assertEquals(taskStackContainer.mChildren.get(stackPos), stack1);
         assertEquals(taskStackContainer.mChildren.get(pinnedStackPos), mPinnedStack);
     }
+
+    @Test
+    public void testDisplayPositionWithPinnedStack() {
+        // The display contains pinned stack that was added in {@link #setUp}.
+        final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
+        final Task task = createTaskInStack(stack, 0 /* userId */);
+
+        // Add another display at top.
+        sWm.mRoot.positionChildAt(WindowContainer.POSITION_TOP, createNewDisplay(),
+                false /* includingParents */);
+
+        // Move the task of {@code mDisplayContent} to top.
+        stack.positionChildAt(WindowContainer.POSITION_TOP, task, true /* includingParents */);
+        final int indexOfDisplayWithPinnedStack = sWm.mRoot.mChildren.indexOf(mDisplayContent);
+
+        assertEquals("The testing DisplayContent should be moved to top with task",
+                sWm.mRoot.getChildCount() - 1, indexOfDisplayWithPinnedStack);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 5fb8997..474e5b7 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -458,12 +458,6 @@
     }
 
     @Override
-    public void setLastInputMethodWindowLw(WindowState ime,
-            WindowState target) {
-
-    }
-
-    @Override
     public void showRecentApps() {
 
     }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
index e648230..0886729 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
@@ -202,8 +202,8 @@
         // When mFrame extends past cf, the content insets are
         // the difference between mFrame and ContentFrame. Visible
         // and stable frames work the same way.
-        final WindowFrames windowFrames = new WindowFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
-        w.computeFrameLw(windowFrames);
+        w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
+        w.computeFrameLw();
         assertFrame(w, 0, 0, 1000, 1000);
         assertContentInset(w, 0, topContentInset, 0, bottomContentInset);
         assertVisibleInset(w, 0, topVisibleInset, 0, bottomVisibleInset);
@@ -217,7 +217,7 @@
         w.mAttrs.width = 100; w.mAttrs.height = 100; //have to clear MATCH_PARENT
         w.mRequestedWidth = 100;
         w.mRequestedHeight = 100;
-        w.computeFrameLw(windowFrames);
+        w.computeFrameLw();
         assertFrame(w, 100, 100, 200, 200);
         assertContentInset(w, 0, 0, 0, 0);
         // In this case the frames are shrunk to the window frame.
@@ -238,8 +238,8 @@
 
         // Here the window has FILL_PARENT, FILL_PARENT
         // so we expect it to fill the entire available frame.
-        final WindowFrames windowFrames = new WindowFrames(pf, pf, pf, pf, pf, pf, pf, pf);
-        w.computeFrameLw(windowFrames);
+        w.getWindowFrames().setFrames(pf, pf, pf, pf, pf, pf, pf, pf);
+        w.computeFrameLw();
         assertFrame(w, 0, 0, 1000, 1000);
 
         // It can select various widths and heights within the bounds.
@@ -247,14 +247,14 @@
         // and we use mRequestedWidth/mRequestedHeight
         w.mAttrs.width = 300;
         w.mAttrs.height = 300;
-        w.computeFrameLw(windowFrames);
+        w.computeFrameLw();
         // Explicit width and height without requested width/height
         // gets us nothing.
         assertFrame(w, 0, 0, 0, 0);
 
         w.mRequestedWidth = 300;
         w.mRequestedHeight = 300;
-        w.computeFrameLw(windowFrames);
+        w.computeFrameLw();
         // With requestedWidth/Height we can freely choose our size within the
         // parent bounds.
         assertFrame(w, 0, 0, 300, 300);
@@ -267,14 +267,14 @@
         w.mRequestedWidth = -1;
         w.mAttrs.width = 100;
         w.mAttrs.height = 100;
-        w.computeFrameLw(windowFrames);
+        w.computeFrameLw();
         assertFrame(w, 0, 0, 100, 100);
         w.mAttrs.flags = 0;
 
         // But sizes too large will be clipped to the containing frame
         w.mRequestedWidth = 1200;
         w.mRequestedHeight = 1200;
-        w.computeFrameLw(windowFrames);
+        w.computeFrameLw();
         assertFrame(w, 0, 0, 1000, 1000);
 
         // Before they are clipped though windows will be shifted
@@ -282,7 +282,7 @@
         w.mAttrs.y = 300;
         w.mRequestedWidth = 1000;
         w.mRequestedHeight = 1000;
-        w.computeFrameLw(windowFrames);
+        w.computeFrameLw();
         assertFrame(w, 0, 0, 1000, 1000);
 
         // If there is room to move around in the parent frame the window will be shifted according
@@ -292,16 +292,16 @@
         w.mRequestedWidth = 300;
         w.mRequestedHeight = 300;
         w.mAttrs.gravity = Gravity.RIGHT | Gravity.TOP;
-        w.computeFrameLw(windowFrames);
+        w.computeFrameLw();
          assertFrame(w, 700, 0, 1000, 300);
         w.mAttrs.gravity = Gravity.RIGHT | Gravity.BOTTOM;
-        w.computeFrameLw(windowFrames);
+        w.computeFrameLw();
         assertFrame(w, 700, 700, 1000, 1000);
         // Window specified  x and y are interpreted as offsets in the opposite
         // direction of gravity
         w.mAttrs.x = 100;
         w.mAttrs.y = 100;
-        w.computeFrameLw(windowFrames);
+        w.computeFrameLw();
         assertFrame(w, 600, 600, 900, 900);
     }
 
@@ -322,8 +322,9 @@
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
-        final WindowFrames windowFrames = new WindowFrames(pf, pf, pf, pf, pf, pf, pf, mEmptyRect);
-        w.computeFrameLw(windowFrames);
+        final WindowFrames windowFrames = w.getWindowFrames();
+        windowFrames.setFrames(pf, pf, pf, pf, pf, pf, pf, mEmptyRect);
+        w.computeFrameLw();
         // For non fullscreen tasks the containing frame is based off the
         // task bounds not the parent frame.
         assertFrame(w, taskLeft, taskTop, taskRight, taskBottom);
@@ -336,7 +337,7 @@
         final int cfBottom = logicalHeight / 2;
         final Rect cf = new Rect(0, 0, cfRight, cfBottom);
         windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect);
-        w.computeFrameLw(windowFrames);
+        w.computeFrameLw();
         assertFrame(w, taskLeft, taskTop, taskRight, taskBottom);
         int contentInsetRight = taskRight - cfRight;
         int contentInsetBottom = taskBottom - cfBottom;
@@ -354,7 +355,7 @@
         final int insetBottom = insetTop + (taskBottom - taskTop);
         task.mInsetBounds.set(insetLeft, insetTop, insetRight, insetBottom);
         windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect);
-        w.computeFrameLw(windowFrames);
+        w.computeFrameLw();
         assertFrame(w, taskLeft, taskTop, taskRight, taskBottom);
         contentInsetRight = insetRight - cfRight;
         contentInsetBottom = insetBottom - cfBottom;
@@ -384,13 +385,14 @@
         // We use a decor content frame with insets to produce cropping.
         Rect dcf = new Rect(cf);
 
-        final WindowFrames windowFrames = new WindowFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
-        w.computeFrameLw(windowFrames);
+        final WindowFrames windowFrames = w.getWindowFrames();
+        windowFrames.setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
+        w.computeFrameLw();
         assertPolicyCrop(w, 0, cf.top, logicalWidth, cf.bottom);
 
         windowFrames.mDecorFrame.setEmpty();
         // Likewise with no decor frame we would get no crop
-        w.computeFrameLw(windowFrames);
+        w.computeFrameLw();
         assertPolicyCrop(w, 0, 0, logicalWidth, logicalHeight);
 
         // Now we set up a window which doesn't fill the entire decor frame.
@@ -404,7 +406,7 @@
         w.mAttrs.height = logicalHeight / 2;
         w.mRequestedWidth = logicalWidth / 2;
         w.mRequestedHeight = logicalHeight / 2;
-        w.computeFrameLw(windowFrames);
+        w.computeFrameLw();
 
         // Normally the crop is shrunk from the decor frame
         // to the computed window frame.
@@ -437,8 +439,9 @@
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
-        final WindowFrames windowFrames = new WindowFrames(pf, pf, pf, pf, pf, pf, pf, mEmptyRect);
-        w.computeFrameLw(windowFrames);
+        final WindowFrames windowFrames = w.getWindowFrames();
+        windowFrames.setFrames(pf, pf, pf, pf, pf, pf, pf, mEmptyRect);
+        w.computeFrameLw();
         // For non fullscreen tasks the containing frame is based off the
         // task bounds not the parent frame.
         assertFrame(w, taskLeft, taskTop, taskRight, taskBottom);
@@ -455,7 +458,7 @@
         pf.set(0, 0, logicalWidth, logicalHeight);
         task.mFullscreenForTest = true;
         windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect);
-        w.computeFrameLw(windowFrames);
+        w.computeFrameLw();
         assertFrame(w, cf.left, cf.top, cf.right, cf.bottom);
         assertContentFrame(w, cf);
         assertContentInset(w, 0, 0, 0, 0);
@@ -473,9 +476,10 @@
         final WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
                 fromBoundingRect(500, 0, 550, 50), pf.width(), pf.height());
 
-        final WindowFrames windowFrames = new WindowFrames(pf, pf, pf, pf, pf, pf, pf, pf);
+        final WindowFrames windowFrames = w.getWindowFrames();
+        windowFrames.setFrames(pf, pf, pf, pf, pf, pf, pf, pf);
         windowFrames.setDisplayCutout(cutout);
-        w.computeFrameLw(windowFrames);
+        w.computeFrameLw();
 
         assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetTop(), 50);
         assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetBottom(), 0);
@@ -497,9 +501,10 @@
         final WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
                 fromBoundingRect(500, 0, 550, 50), pf.width(), pf.height());
 
-        final WindowFrames windowFrames = new WindowFrames(pf, pf, pf, pf, pf, pf, pf, pf);
+        final WindowFrames windowFrames = w.getWindowFrames();
+        windowFrames.setFrames(pf, pf, pf, pf, pf, pf, pf, pf);
         windowFrames.setDisplayCutout(cutout);
-        w.computeFrameLw(windowFrames);
+        w.computeFrameLw();
 
         assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetTop(), 50);
         assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetBottom(), 0);
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
index b43d9a6..b7cc9ce 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
@@ -76,7 +76,8 @@
  */
 @SmallTest
 @FlakyTest(bugId = 74078662)
-@Presubmit
+// TODO(b/116597907): Re-enable this test in postsubmit after the bug is fixed.
+// @Presubmit
 @RunWith(AndroidJUnit4.class)
 public class WindowStateTests extends WindowTestsBase {
 
@@ -369,36 +370,45 @@
         final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
 
         app.mHasSurface = true;
-        app.mToken.mSurfaceControl = mock(SurfaceControl.class);
+        app.mSurfaceControl = mock(SurfaceControl.class);
         try {
             app.getFrameLw().set(10, 20, 60, 80);
+            app.updateSurfacePosition(t);
 
             app.seamlesslyRotateIfAllowed(t, ROTATION_0, ROTATION_90, true);
 
             assertTrue(app.mSeamlesslyRotated);
+
+            // Verify we un-rotate the window state surface.
             Matrix matrix = new Matrix();
             // Un-rotate 90 deg
             matrix.setRotate(270);
             // Translate it back to origin
             matrix.postTranslate(0, mDisplayInfo.logicalWidth);
-            verify(t).setMatrix(eq(app.mToken.mSurfaceControl), eq(matrix), any(float[].class));
+            verify(t).setMatrix(eq(app.mSurfaceControl), eq(matrix), any(float[].class));
+
+            // Verify we update the position as well.
+            float[] currentSurfacePos = {app.mLastSurfacePosition.x, app.mLastSurfacePosition.y};
+            matrix.mapPoints(currentSurfacePos);
+            verify(t).setPosition(eq(app.mSurfaceControl), eq(currentSurfacePos[0]),
+                    eq(currentSurfacePos[1]));
         } finally {
+            app.mSurfaceControl = null;
             app.mHasSurface = false;
-            app.mToken.mSurfaceControl = null;
         }
     }
 
     @Test
     public void testDisplayCutoutIsCalculatedRelativeToFrame() {
         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
-        WindowFrames wf = new WindowFrames();
+        WindowFrames wf = app.getWindowFrames();
         wf.mParentFrame.set(7, 10, 185, 380);
         wf.mDisplayFrame.set(wf.mParentFrame);
         final DisplayCutout cutout = new DisplayCutout(new Rect(0, 15, 0, 22),
                 Arrays.asList(new Rect(95, 0, 105, 15), new Rect(95, 378, 105, 400)));
         wf.setDisplayCutout(new WmDisplayCutout(cutout, new Size(200, 400)));
 
-        app.computeFrameLw(wf);
+        app.computeFrameLw();
         assertThat(app.getWmDisplayCutout().getDisplayCutout(), is(cutout.inset(7, 10, 5, 20)));
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java b/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java
index bbc6550..01b7c4f 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java
@@ -59,7 +59,8 @@
  */
 @SmallTest
 @FlakyTest(bugId = 74078662)
-@Presubmit
+// TODO(b/116597907): Re-enable this test in postsubmit after the bug is fixed.
+// @Presubmit
 @RunWith(AndroidJUnit4.class)
 public class WindowTracingTest extends WindowTestsBase {
 
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index 95d4a15..659c6e7 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -20,6 +20,7 @@
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertTrue;
 
 import static org.mockito.Matchers.any;
@@ -34,6 +35,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.ServiceConnection;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
@@ -47,6 +49,9 @@
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.IntArray;
+import android.util.SparseArray;
 import android.util.Xml;
 
 import com.android.internal.util.FastXmlSerializer;
@@ -68,7 +73,9 @@
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
+import java.util.Set;
 
 public class ManagedServicesTest extends UiServiceTestCase {
 
@@ -113,7 +120,12 @@
             when(mUm.getUserInfo(eq(user.id))).thenReturn(user);
         }
         when(mUm.getUsers()).thenReturn(users);
-        when(mUserProfiles.getCurrentProfileIds()).thenReturn(new int[] {0, 10, 11, 12});
+        IntArray profileIds = new IntArray();
+        profileIds.add(0);
+        profileIds.add(11);
+        profileIds.add(10);
+        profileIds.add(12);
+        when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds);
 
         mExpectedPrimaryPackages = new ArrayMap<>();
         mExpectedPrimaryPackages.put(0, "this.is.a.package.name:another.package");
@@ -165,12 +177,12 @@
 
     @Test
     public void testBackupAndRestore_migration_preO() throws Exception {
-        ArrayMap backupPrimaryPackages = new ArrayMap<>();
+        ArrayMap<Integer, String> backupPrimaryPackages = new ArrayMap<>();
         backupPrimaryPackages.put(0, "backup.0:backup:0a");
         backupPrimaryPackages.put(10, "10.backup");
         backupPrimaryPackages.put(11, "eleven");
         backupPrimaryPackages.put(12, "");
-        ArrayMap backupPrimaryComponentNames = new ArrayMap<>();
+        ArrayMap<Integer, String> backupPrimaryComponentNames = new ArrayMap<>();
         backupPrimaryComponentNames.put(0, "backup.first/whatever:a/b");
         backupPrimaryComponentNames.put(10, "again/M1");
         backupPrimaryComponentNames.put(11, "orange/youglad:itisnot/banana");
@@ -179,11 +191,11 @@
         backupPrimary.put(APPROVAL_BY_PACKAGE, backupPrimaryPackages);
         backupPrimary.put(APPROVAL_BY_COMPONENT, backupPrimaryComponentNames);
 
-        ArrayMap backupSecondaryComponentNames = new ArrayMap<>();
+        ArrayMap<Integer, String> backupSecondaryComponentNames = new ArrayMap<>();
         backupSecondaryComponentNames.put(0, "secondary.1/component.Name");
         backupSecondaryComponentNames.put(10,
                 "this.is.another.package.backup/with.Component:component.backup/2");
-        ArrayMap backupSecondaryPackages = new ArrayMap<>();
+        ArrayMap<Integer, String> backupSecondaryPackages = new ArrayMap<>();
         backupSecondaryPackages.put(0, "");
         backupSecondaryPackages.put(10,
                 "this.is.another.package.backup:package.backup");
@@ -368,7 +380,7 @@
             serializer.endDocument();
             serializer.flush();
 
-            for (int userId : mUserProfiles.getCurrentProfileIds()) {
+            for (int userId : mUserProfiles.getCurrentProfileIds().toArray()) {
                 List<String> expected =
                         stringToList(mExpectedPrimary.get(approvalLevel).get(userId));
                 List<String> actual = stringToList(Settings.Secure.getStringForUser(
@@ -633,7 +645,7 @@
     }
 
     @Test
-    public void testGetAllowedComponents() throws Exception {
+    public void testGetAllowedComponentsByUser() throws Exception {
         ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
                 APPROVAL_BY_COMPONENT);
         loadXml(service);
@@ -708,6 +720,145 @@
         assertTrue(services.isSameUser(service, 10));
     }
 
+    @Test
+    public void testGetAllowedComponents() throws Exception {
+        ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
+                APPROVAL_BY_COMPONENT);
+        loadXml(service);
+
+        SparseArray<ArraySet<ComponentName>> expected = new SparseArray<>();
+
+        ArraySet<ComponentName> expected10 = new ArraySet<>();
+        expected10.add(ComponentName.unflattenFromString("this.is.another.package/M1"));
+        expected10.add(ComponentName.unflattenFromString("this.is.another.package/with.Component"));
+        expected10.add(ComponentName.unflattenFromString("component/2"));
+        expected10.add(ComponentName.unflattenFromString("package/component2"));
+        expected.put(10, expected10);
+        ArraySet<ComponentName> expected0 = new ArraySet<>();
+        expected0.add(ComponentName.unflattenFromString("secondary/component.Name"));
+        expected0.add(ComponentName.unflattenFromString("this.is.a.package.name/Ba"));
+        expected0.add(ComponentName.unflattenFromString("another.package/B1"));
+        expected.put(0, expected0);
+        ArraySet<ComponentName> expected12 = new ArraySet<>();
+        expected12.add(ComponentName.unflattenFromString("bananas!/Bananas!"));
+        expected.put(12, expected12);
+        expected.put(11, new ArraySet<>());
+
+        SparseArray<ArraySet<ComponentName>> actual =
+                service.getAllowedComponents(mUserProfiles.getCurrentProfileIds());
+
+        assertContentsInAnyOrder(expected, actual);
+    }
+
+    @Test
+    public void testPopulateComponentsToUnbind_forceRebind() {
+        ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
+                APPROVAL_BY_COMPONENT);
+
+        IInterface iInterface = mock(IInterface.class);
+        when(iInterface.asBinder()).thenReturn(mock(IBinder.class));
+
+        ManagedServices.ManagedServiceInfo service0 = service.new ManagedServiceInfo(
+                iInterface, ComponentName.unflattenFromString("a/a"), 0, false,
+                mock(ServiceConnection.class), 26);
+        ManagedServices.ManagedServiceInfo service10 = service.new ManagedServiceInfo(
+                iInterface, ComponentName.unflattenFromString("b/b"), 10, false,
+                mock(ServiceConnection.class), 26);
+        Set<ManagedServices.ManagedServiceInfo> removableBoundServices = new ArraySet<>();
+        removableBoundServices.add(service0);
+        removableBoundServices.add(service10);
+
+        SparseArray<Set<ComponentName>> allowedComponentsToBind = new SparseArray<>();
+        Set<ComponentName> allowed0 = new ArraySet<>();
+        allowed0.add(ComponentName.unflattenFromString("a/a"));
+        allowedComponentsToBind.put(0, allowed0);
+        Set<ComponentName> allowed10 = new ArraySet<>();
+        allowed10.add(ComponentName.unflattenFromString("b/b"));
+        allowedComponentsToBind.put(10, allowed10);
+
+        SparseArray<Set<ComponentName>> componentsToUnbind = new SparseArray<>();
+
+        service.populateComponentsToUnbind(true, removableBoundServices, allowedComponentsToBind,
+                componentsToUnbind);
+
+        assertEquals(2, componentsToUnbind.size());
+        assertTrue(componentsToUnbind.get(0).contains(ComponentName.unflattenFromString("a/a")));
+        assertTrue(componentsToUnbind.get(10).contains(ComponentName.unflattenFromString("b/b")));
+    }
+
+    @Test
+    public void testPopulateComponentsToUnbind() {
+        ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
+                APPROVAL_BY_COMPONENT);
+
+        IInterface iInterface = mock(IInterface.class);
+        when(iInterface.asBinder()).thenReturn(mock(IBinder.class));
+
+        ManagedServices.ManagedServiceInfo service0 = service.new ManagedServiceInfo(
+                iInterface, ComponentName.unflattenFromString("a/a"), 0, false,
+                mock(ServiceConnection.class), 26);
+        ManagedServices.ManagedServiceInfo service0a = service.new ManagedServiceInfo(
+                iInterface, ComponentName.unflattenFromString("c/c"), 0, false,
+                mock(ServiceConnection.class), 26);
+        ManagedServices.ManagedServiceInfo service10 = service.new ManagedServiceInfo(
+                iInterface, ComponentName.unflattenFromString("b/b"), 10, false,
+                mock(ServiceConnection.class), 26);
+        Set<ManagedServices.ManagedServiceInfo> removableBoundServices = new ArraySet<>();
+        removableBoundServices.add(service0);
+        removableBoundServices.add(service0a);
+        removableBoundServices.add(service10);
+
+        SparseArray<Set<ComponentName>> allowedComponentsToBind = new SparseArray<>();
+        Set<ComponentName> allowed0 = new ArraySet<>();
+        allowed0.add(ComponentName.unflattenFromString("a/a"));
+        allowedComponentsToBind.put(0, allowed0);
+        Set<ComponentName> allowed10 = new ArraySet<>();
+        allowed10.add(ComponentName.unflattenFromString("b/b"));
+        allowedComponentsToBind.put(10, allowed10);
+
+        SparseArray<Set<ComponentName>> componentsToUnbind = new SparseArray<>();
+
+        service.populateComponentsToUnbind(false, removableBoundServices, allowedComponentsToBind,
+                componentsToUnbind);
+
+        assertEquals(1, componentsToUnbind.size());
+        assertEquals(1, componentsToUnbind.get(0).size());
+        assertTrue(componentsToUnbind.get(0).contains(ComponentName.unflattenFromString("c/c")));
+    }
+
+    @Test
+    public void populateComponentsToBind() {
+        ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
+                APPROVAL_BY_COMPONENT);
+
+        SparseArray<ArraySet<ComponentName>> approvedComponentsByUser = new SparseArray<>();
+        ArraySet<ComponentName> allowed0 = new ArraySet<>();
+        allowed0.add(ComponentName.unflattenFromString("a/a"));
+        approvedComponentsByUser.put(0, allowed0);
+        ArraySet<ComponentName> allowed10 = new ArraySet<>();
+        allowed10.add(ComponentName.unflattenFromString("b/b"));
+        allowed10.add(ComponentName.unflattenFromString("c/c"));
+        approvedComponentsByUser.put(10, allowed10);
+        ArraySet<ComponentName> allowed15 = new ArraySet<>();
+        allowed15.add(ComponentName.unflattenFromString("d/d"));
+        approvedComponentsByUser.put(15, allowed15);
+
+        IntArray users = new IntArray();
+        users.add(10);
+        users.add(0);
+
+        SparseArray<Set<ComponentName>> componentsToBind = new SparseArray<>();
+
+        service.populateComponentsToBind(componentsToBind, users, approvedComponentsByUser);
+
+        assertEquals(2, componentsToBind.size());
+        assertEquals(1, componentsToBind.get(0).size());
+        assertTrue(componentsToBind.get(0).contains(ComponentName.unflattenFromString("a/a")));
+        assertEquals(2, componentsToBind.get(10).size());
+        assertTrue(componentsToBind.get(10).contains(ComponentName.unflattenFromString("b/b")));
+        assertTrue(componentsToBind.get(10).contains(ComponentName.unflattenFromString("c/c")));
+    }
+
     private void loadXml(ManagedServices service) throws Exception {
         final StringBuffer xml = new StringBuffer();
         xml.append("<" + service.getConfig().xmlTag + ">\n");
@@ -775,7 +926,8 @@
                 ManagedServices.ENABLED_SERVICES_SEPARATOR)));
     }
 
-    private void assertContentsInAnyOrder(List<?> expected, List<?> actual) {
+    private void assertContentsInAnyOrder(Collection<?> expected, Collection<?> actual) {
+        assertNotNull(actual);
         assertEquals(expected.size(), actual.size());
 
         for (Object o : expected) {
@@ -787,6 +939,21 @@
         }
     }
 
+    private void assertContentsInAnyOrder(SparseArray<ArraySet<ComponentName>> expected,
+            SparseArray<ArraySet<ComponentName>> actual) throws Exception {
+        assertEquals(expected.size(), actual.size());
+
+        for (int i = 0; i < expected.size(); i++) {
+            int key = expected.keyAt(i);
+            assertTrue(actual.indexOfKey(key) >= 0);
+            try {
+                assertContentsInAnyOrder(expected.valueAt(i), actual.get(key));
+            } catch (Throwable t) {
+                throw new Exception("Error validating " + key, t);
+            }
+        }
+    }
+
     private void verifyExpectedBoundEntries(ManagedServices service, boolean primary)
             throws Exception {
         ArrayMap<Integer, String> verifyMap = primary ? mExpectedPrimary.get(service.mApprovalLevel)
@@ -920,7 +1087,7 @@
 
         @Override
         protected boolean checkType(IInterface service) {
-            return false;
+            return true;
         }
 
         @Override
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
index f9a4f78..1de1e4e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
@@ -33,6 +33,7 @@
 import android.content.pm.ServiceInfo;
 import android.content.pm.UserInfo;
 import android.os.UserManager;
+import android.util.IntArray;
 import android.util.Xml;
 
 import com.android.internal.util.FastXmlSerializer;
@@ -103,7 +104,12 @@
         }
         when(mUm.getUsers()).thenReturn(users);
         when(mUm.getUsers(anyBoolean())).thenReturn(users);
-        when(mUserProfiles.getCurrentProfileIds()).thenReturn(new int[] {0, 10, 11, 12});
+        IntArray profileIds = new IntArray();
+        profileIds.add(0);
+        profileIds.add(11);
+        profileIds.add(10);
+        profileIds.add(12);
+        when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds);
     }
 
     @Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index a1b3b98..45d2fa2 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -97,6 +97,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.MediaStore;
 import android.provider.Settings.Secure;
 import android.service.notification.Adjustment;
@@ -519,8 +520,9 @@
         NotificationChannel channel = new NotificationChannel("id", "name",
                 IMPORTANCE_HIGH);
         NotificationRecord r = generateNotificationRecord(channel);
-        assertTrue(mService.isBlocked(r, mUsageStats));
-        verify(mUsageStats, times(1)).registerSuspendedByAdmin(eq(r));
+
+        // isBlocked is only used for user blocking, not app suspension
+        assertFalse(mService.isBlocked(r, mUsageStats));
     }
 
     @Test
@@ -3381,10 +3383,44 @@
     }
 
     @Test
+    public void testIsCallerInstantApp_primaryUser() throws Exception {
+        ApplicationInfo info = new ApplicationInfo();
+        info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT;
+        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(0))).thenReturn(info);
+
+        assertTrue(mService.isCallerInstantApp("any", 45770, 0));
+
+        info.privateFlags = 0;
+        assertFalse(mService.isCallerInstantApp("any", 575370, 0));
+    }
+
+    @Test
+    public void testIsCallerInstantApp_secondaryUser() throws Exception {
+        ApplicationInfo info = new ApplicationInfo();
+        info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT;
+        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(10))).thenReturn(info);
+        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(0))).thenReturn(null);
+
+        assertTrue(mService.isCallerInstantApp("any", 68638450, 10));
+    }
+
+    @Test
+    public void testResolveNotificationUid_sameApp_nonSystemUser() throws Exception {
+        ApplicationInfo info = new ApplicationInfo();
+        info.uid = Binder.getCallingUid();
+        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(10))).thenReturn(info);
+        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(0))).thenReturn(null);
+
+        int actualUid = mService.resolveNotificationUid("caller", "caller", info.uid, 10);
+
+        assertEquals(info.uid, actualUid);
+    }
+
+    @Test
     public void testResolveNotificationUid_sameApp() throws Exception {
         ApplicationInfo info = new ApplicationInfo();
         info.uid = Binder.getCallingUid();
-        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), anyInt())).thenReturn(info);
+        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(0))).thenReturn(info);
 
         int actualUid = mService.resolveNotificationUid("caller", "caller", info.uid, 0);
 
@@ -3453,4 +3489,46 @@
             // yay
         }
     }
+
+    @Test
+    public void testRemoveForegroundServiceFlagFromNotification_enqueued() {
+        Notification n = new Notification.Builder(mContext, "").build();
+        n.flags |= FLAG_FOREGROUND_SERVICE;
+
+        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 9, null, mUid, 0,
+                n, new UserHandle(mUid), null, 0);
+        NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+        mService.addEnqueuedNotification(r);
+
+        mInternalService.removeForegroundServiceFlagFromNotification(
+                PKG, r.sbn.getId(), r.sbn.getUserId());
+
+        waitForIdle();
+
+        verify(mListeners, timeout(200).times(0)).notifyPostedLocked(any(), any());
+    }
+
+    @Test
+    public void testRemoveForegroundServiceFlagFromNotification_posted() {
+        Notification n = new Notification.Builder(mContext, "").build();
+        n.flags |= FLAG_FOREGROUND_SERVICE;
+
+        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 9, null, mUid, 0,
+                n, new UserHandle(mUid), null, 0);
+        NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+        mService.addNotification(r);
+
+        mInternalService.removeForegroundServiceFlagFromNotification(
+                PKG, r.sbn.getId(), r.sbn.getUserId());
+
+        waitForIdle();
+
+        ArgumentCaptor<NotificationRecord> captor =
+                ArgumentCaptor.forClass(NotificationRecord.class);
+        verify(mListeners, times(1)).notifyPostedLocked(captor.capture(), any());
+
+        assertEquals(0, captor.getValue().getNotification().flags);
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 750345b..79998a5 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -284,8 +284,8 @@
         compareChannels(channel2,
                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false));
 
-        List<NotificationChannelGroup> actualGroups =
-                mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1, false, true).getList();
+        List<NotificationChannelGroup> actualGroups = mHelper.getNotificationChannelGroups(
+                PKG_N_MR1, UID_N_MR1, false, true, false).getList();
         boolean foundNcg = false;
         for (NotificationChannelGroup actual : actualGroups) {
             if (ncg.getId().equals(actual.getId())) {
@@ -354,8 +354,8 @@
         compareChannels(channel3,
                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3.getId(), false));
 
-        List<NotificationChannelGroup> actualGroups =
-                mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1, false, true).getList();
+        List<NotificationChannelGroup> actualGroups = mHelper.getNotificationChannelGroups(
+                PKG_N_MR1, UID_N_MR1, false, true, false).getList();
         boolean foundNcg = false;
         for (NotificationChannelGroup actual : actualGroups) {
             if (ncg.getId().equals(actual.getId())) {
@@ -1350,8 +1350,8 @@
         mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG_N_MR1}, new int[]{
                 UID_N_MR1});
 
-        assertEquals(0,
-                mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1, true, true).getList().size());
+        assertEquals(0, mHelper.getNotificationChannelGroups(
+                PKG_N_MR1, UID_N_MR1, true, true, false).getList().size());
     }
 
     @Test
@@ -1440,8 +1440,8 @@
                 new NotificationChannel("id3", "name1", NotificationManager.IMPORTANCE_HIGH);
         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false);
 
-        List<NotificationChannelGroup> actual =
-                mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1, true, true).getList();
+        List<NotificationChannelGroup> actual = mHelper.getNotificationChannelGroups(
+                PKG_N_MR1, UID_N_MR1, true, true, false).getList();
         assertEquals(3, actual.size());
         for (NotificationChannelGroup group : actual) {
             if (group.getId() == null) {
@@ -1473,13 +1473,13 @@
                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
         channel1.setGroup(ncg.getId());
         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
-        mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1, true, true).getList();
+        mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1, true, true, false).getList();
 
         channel1.setImportance(IMPORTANCE_LOW);
         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true);
 
-        List<NotificationChannelGroup> actual =
-                mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1, true, true).getList();
+        List<NotificationChannelGroup> actual = mHelper.getNotificationChannelGroups(
+                PKG_N_MR1, UID_N_MR1, true, true, false).getList();
 
         assertEquals(2, actual.size());
         for (NotificationChannelGroup group : actual) {
@@ -1490,6 +1490,32 @@
     }
 
     @Test
+    public void testGetChannelGroups_includeEmptyGroups() {
+        NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
+        NotificationChannelGroup ncgEmpty = new NotificationChannelGroup("group2", "name2");
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncgEmpty, true);
+
+        NotificationChannel channel1 =
+                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
+        channel1.setGroup(ncg.getId());
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
+
+        List<NotificationChannelGroup> actual = mHelper.getNotificationChannelGroups(
+                PKG_N_MR1, UID_N_MR1, false, false, true).getList();
+
+        assertEquals(2, actual.size());
+        for (NotificationChannelGroup group : actual) {
+            if (Objects.equals(group.getId(), ncg.getId())) {
+                assertEquals(1, group.getChannels().size());
+            }
+            if (Objects.equals(group.getId(), ncgEmpty.getId())) {
+                assertEquals(0, group.getChannels().size());
+            }
+        }
+    }
+
+    @Test
     public void testCreateChannel_updateName() throws Exception {
         NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT);
         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
index 88c6fcf..b955e56 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
@@ -32,6 +32,7 @@
 import android.service.notification.StatusBarNotification;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.util.IntArray;
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
@@ -235,18 +236,22 @@
         mSnoozeHelper.snooze(r2, 1000);
         mSnoozeHelper.snooze(r3, 1000);
         mSnoozeHelper.snooze(r4, 1000);
-        when(mUserProfiles.getCurrentProfileIds()).thenReturn(
-                new int[] {UserHandle.USER_SYSTEM});
+        IntArray profileIds = new IntArray();
+        profileIds.add(UserHandle.USER_SYSTEM);
+        when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds);
         assertEquals(3, mSnoozeHelper.getSnoozed().size());
-        when(mUserProfiles.getCurrentProfileIds()).thenReturn(
-                new int[] {UserHandle.USER_CURRENT});
+        profileIds = new IntArray();
+        profileIds.add(UserHandle.USER_CURRENT);
+        when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds);
         assertEquals(1, mSnoozeHelper.getSnoozed().size());
     }
 
     @Test
     public void testGetSnoozedByUser_managedProfiles() throws Exception {
-        when(mUserProfiles.getCurrentProfileIds()).thenReturn(
-                new int[] {UserHandle.USER_SYSTEM, UserHandle.USER_CURRENT});
+        IntArray profileIds = new IntArray();
+        profileIds.add(UserHandle.USER_CURRENT);
+        profileIds.add(UserHandle.USER_SYSTEM);
+        when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds);
         NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
         NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM);
         NotificationRecord r3 = getNotificationRecord("pkg2", 3, "three", UserHandle.SYSTEM);
@@ -273,8 +278,9 @@
 
     @Test
     public void repostGroupSummary_repostsSummary() throws Exception {
-        when(mUserProfiles.getCurrentProfileIds()).thenReturn(
-                new int[] {UserHandle.USER_SYSTEM});
+        IntArray profileIds = new IntArray();
+        profileIds.add(UserHandle.USER_SYSTEM);
+        when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds);
         NotificationRecord r = getNotificationRecord(
                 "pkg", 1, "one", UserHandle.SYSTEM, "group1", true);
         NotificationRecord r2 = getNotificationRecord(
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
new file mode 100644
index 0000000..100f9c6
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distriZenbuted on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.notification;
+
+import static junit.framework.Assert.assertEquals;
+
+import android.app.NotificationManager.Policy;
+import android.service.notification.ZenModeConfig;
+import android.service.notification.ZenPolicy;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.server.UiServiceTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ZenModeConfigTest extends UiServiceTestCase {
+
+    @Test
+    public void testPriorityOnlyMutingAllNotifications() {
+        ZenModeConfig config = getMutedNotificationsConfig();
+        assertEquals(true, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+
+        config.allowReminders = true;
+        assertEquals(false, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+        config.allowReminders = false;
+
+        config.areChannelsBypassingDnd = true;
+        assertEquals(false, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+        config.areChannelsBypassingDnd = false;
+
+        assertEquals(true, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+    }
+
+    @Test
+    public void testZenPolicyNothingSetToNotificationPolicy() {
+        ZenModeConfig config = getMutedAllConfig();
+        ZenPolicy zenPolicy = new ZenPolicy.Builder().build();
+        assertEquals(config.toNotificationPolicy(), config.toNotificationPolicy(zenPolicy));
+    }
+
+    @Test
+    public void testZenPolicyToNotificationPolicy() {
+        ZenModeConfig config = getMutedAllConfig();
+        config.suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_BADGE;
+
+        ZenPolicy zenPolicy = new ZenPolicy.Builder()
+                .allowAlarms(true)
+                .allowReminders(true)
+                .allowEvents(true)
+                .showLights(false)
+                .showInAmbientDisplay(false)
+                .build();
+
+        Policy originalPolicy = config.toNotificationPolicy();
+        int priorityCategories = originalPolicy.priorityCategories;
+        int priorityCallSenders = originalPolicy.priorityCallSenders;
+        int priorityMessageSenders = originalPolicy.priorityMessageSenders;
+        int suppressedVisualEffects = originalPolicy.suppressedVisualEffects;
+        priorityCategories |= Policy.PRIORITY_CATEGORY_ALARMS;
+        priorityCategories |= Policy.PRIORITY_CATEGORY_REMINDERS;
+        priorityCategories |= Policy.PRIORITY_CATEGORY_EVENTS;
+        suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_LIGHTS;
+        suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_AMBIENT;
+
+        Policy expectedPolicy = new Policy(priorityCategories, priorityCallSenders,
+                priorityMessageSenders, suppressedVisualEffects);
+
+        assertEquals(expectedPolicy, config.toNotificationPolicy(zenPolicy));
+    }
+
+    @Test
+    public void testPriorityOnlyMutingAll() {
+        ZenModeConfig config = getMutedAllConfig();
+        assertEquals(true, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+        assertEquals(true, ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
+
+        config.allowReminders = true;
+        assertEquals(false, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+        assertEquals(false, ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
+        config.allowReminders = false;
+
+        config.areChannelsBypassingDnd = true;
+        assertEquals(false, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+        assertEquals(false, ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
+        config.areChannelsBypassingDnd = false;
+
+        config.allowAlarms = true;
+        assertEquals(true, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+        assertEquals(false, ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
+        config.allowAlarms = false;
+
+        assertEquals(true, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+        assertEquals(true, ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
+    }
+
+    private ZenModeConfig getMutedNotificationsConfig() {
+        ZenModeConfig config = new ZenModeConfig();
+        // Allow alarms, media, and system
+        config.allowAlarms = true;
+        config.allowMedia = true;
+        config.allowSystem = true;
+
+        // All notification sounds are not allowed
+        config.allowCalls = false;
+        config.allowRepeatCallers = false;
+        config.allowMessages = false;
+        config.allowReminders = false;
+        config.allowEvents = false;
+        config.areChannelsBypassingDnd = false;
+
+        config.suppressedVisualEffects = 0;
+
+        return config;
+    }
+
+    private ZenModeConfig getMutedAllConfig() {
+        ZenModeConfig config = new ZenModeConfig();
+        // No sounds allowed
+        config.allowAlarms = false;
+        config.allowMedia = false;
+        config.allowSystem = false;
+        config.allowCalls = false;
+        config.allowRepeatCallers = false;
+        config.allowMessages = false;
+        config.allowReminders = false;
+        config.allowEvents = false;
+        config.areChannelsBypassingDnd = false;
+
+        config.suppressedVisualEffects = 0;
+        return config;
+    }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 91f4bc8..702161e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -45,6 +45,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
 import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.AudioManagerInternal;
@@ -60,6 +61,7 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.util.ArrayMap;
+import android.util.Log;
 import android.util.Xml;
 
 import com.android.internal.R;
@@ -74,12 +76,16 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
@@ -88,7 +94,7 @@
 
     ConditionProviders mConditionProviders;
     @Mock NotificationManager mNotificationManager;
-    @Mock private Resources mResources;
+    private Resources mResources;
     private TestableLooper mTestableLooper;
     private ZenModeHelper mZenModeHelperSpy;
     private Context mContext;
@@ -101,11 +107,17 @@
         mTestableLooper = TestableLooper.get(this);
         mContext = spy(getContext());
         mContentResolver = mContext.getContentResolver();
-        when(mContext.getResources()).thenReturn(mResources);
-        when(mResources.getString(R.string.zen_mode_default_every_night_name)).thenReturn("night");
-        when(mResources.getString(R.string.zen_mode_default_events_name)).thenReturn("events");
-        when(mContext.getSystemService(NotificationManager.class)).thenReturn(mNotificationManager);
 
+        mResources = spy(mContext.getResources());
+        try {
+            when(mResources.getXml(R.xml.default_zen_mode_config)).thenReturn(
+                    getDefaultConfigParser());
+        } catch (Exception e) {
+            Log.d("ZenModeHelperTest", "Couldn't mock default zen mode config xml file err=" +
+                    e.toString());
+        }
+
+        when(mContext.getSystemService(NotificationManager.class)).thenReturn(mNotificationManager);
         mConditionProviders = new ConditionProviders(mContext, new UserProfiles(),
                 AppGlobals.getPackageManager());
         mConditionProviders.addSystemProvider(new CountdownConditionProvider());
@@ -113,6 +125,30 @@
                 mConditionProviders));
     }
 
+    private XmlResourceParser getDefaultConfigParser() throws IOException, XmlPullParserException {
+        String xml = "<zen version=\"8\" user=\"0\">\n"
+                + "<allow calls=\"false\" repeatCallers=\"false\" messages=\"true\" "
+                + "reminders=\"false\" events=\"false\" callsFrom=\"1\" messagesFrom=\"2\" "
+                + "visualScreenOff=\"true\" alarms=\"true\" "
+                + "media=\"true\" system=\"false\" />\n"
+                + "<automatic ruleId=\"EVENTS_DEFAULT_RULE\" enabled=\"false\" snoozing=\"false\""
+                + " name=\"Event\" zen=\"1\""
+                + " component=\"android/com.android.server.notification.EventConditionProvider\""
+                + " conditionId=\"condition://android/event?userId=-10000&amp;calendar=&amp;"
+                + "reply=1\"/>\n"
+                + "<automatic ruleId=\"EVERY_NIGHT_DEFAULT_RULE\" enabled=\"false\""
+                + " snoozing=\"false\" name=\"Sleeping\" zen=\"1\""
+                + " component=\"android/com.android.server.notification.ScheduleConditionProvider\""
+                + " conditionId=\"condition://android/schedule?days=1.2.3.4.5.6.7 &amp;start=22.0"
+                + "&amp;end=7.0&amp;exitAtAlarm=true\"/>"
+                + "<disallow visualEffects=\"511\" />"
+                + "</zen>";
+        XmlPullParser parser = Xml.newPullParser();
+        parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())), null);
+        parser.nextTag();
+        return new XmlResourceParserImpl(parser);
+    }
+
     private ByteArrayOutputStream writeXmlAndPurge(boolean forBackup, Integer version)
             throws Exception {
         XmlSerializer serializer = new FastXmlSerializer();
@@ -649,8 +685,8 @@
         customRule.id = "customRule";
         customRule.name = "Custom Rule";
         customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
-        customRule.component = new ComponentName("test", "test");
         customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo);
+        customRule.component = new ComponentName("android", "ScheduleConditionProvider");
         automaticRules.put("customRule", customRule);
         mZenModeHelperSpy.mConfig.automaticRules = automaticRules;
 
@@ -662,8 +698,8 @@
                 new ByteArrayInputStream(baos.toByteArray())), null);
         parser.nextTag();
         mZenModeHelperSpy.readXml(parser, true);
-        assertEquals(original.hashCode(), mZenModeHelperSpy.mConfig.hashCode());
         assertEquals(original, mZenModeHelperSpy.mConfig);
+        assertEquals(original.hashCode(), mZenModeHelperSpy.mConfig.hashCode());
     }
 
     @Test
@@ -678,6 +714,7 @@
         customRule.name = "Custom Rule";
         customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         customRule.conditionId = ZenModeConfig.toScheduleConditionId(weeknights);
+        customRule.component = new ComponentName("android", "ScheduleConditionProvider");
         enabledAutoRule.put("customRule", customRule);
         mZenModeHelperSpy.mConfig.automaticRules = enabledAutoRule;
 
@@ -842,6 +879,7 @@
         customRule.name = "Custom Rule";
         customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         customRule.conditionId = ZenModeConfig.toScheduleConditionId(weeknights);
+        customRule.component = new ComponentName("android", "ScheduleConditionProvider");
         disabledAutoRule.put("customRule", customRule);
         mZenModeHelperSpy.mConfig.automaticRules = disabledAutoRule;
 
@@ -877,6 +915,7 @@
         customRule.name = "Custom Rule";
         customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo);
+        customRule.component = new ComponentName("android", "ScheduleConditionProvider");
         automaticRules.put("customRule", customRule);
 
         ZenModeConfig.ZenRule defaultScheduleRule = new ZenModeConfig.ZenRule();
@@ -886,6 +925,7 @@
         defaultScheduleRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         defaultScheduleRule.conditionId = ZenModeConfig.toScheduleConditionId(
                 defaultScheduleRuleInfo);
+        customRule.component = new ComponentName("android", "ScheduleConditionProvider");
         defaultScheduleRule.id = ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID;
         automaticRules.put(ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID, defaultScheduleRule);
 
@@ -922,6 +962,7 @@
         customRule.name = "Custom Rule";
         customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo);
+        customRule.component = new ComponentName("android", "ScheduleConditionProvider");
         automaticRules.put("customRule", customRule);
 
         ZenModeConfig.ZenRule defaultScheduleRule = new ZenModeConfig.ZenRule();
@@ -1015,4 +1056,294 @@
         assertTrue(mZenModeHelperSpy.mConfig.allowRepeatCallers);
         assertEquals(SUPPRESSED_EFFECT_BADGE, mZenModeHelperSpy.mConfig.suppressedVisualEffects);
     }
+
+    /**
+     * Wrapper to use XmlPullParser as XmlResourceParser for Resources.getXml()
+     */
+    final class XmlResourceParserImpl implements XmlResourceParser {
+        private XmlPullParser parser;
+
+        public XmlResourceParserImpl(XmlPullParser parser) {
+            this.parser = parser;
+        }
+
+        public int getEventType() throws XmlPullParserException {
+            return parser.getEventType();
+        }
+
+        @Override
+        public void setFeature(String name, boolean state) throws XmlPullParserException {
+            parser.setFeature(name, state);
+        }
+
+        @Override
+        public boolean getFeature(String name) {
+            return false;
+        }
+
+        @Override
+        public void setProperty(String name, Object value) throws XmlPullParserException {
+            parser.setProperty(name, value);
+        }
+
+        @Override
+        public Object getProperty(String name) {
+            return parser.getProperty(name);
+        }
+
+        @Override
+        public void setInput(Reader in) throws XmlPullParserException {
+            parser.setInput(in);
+        }
+
+        @Override
+        public void setInput(InputStream inputStream, String inputEncoding)
+                throws XmlPullParserException {
+            parser.setInput(inputStream, inputEncoding);
+        }
+
+        @Override
+        public String getInputEncoding() {
+            return parser.getInputEncoding();
+        }
+
+        @Override
+        public void defineEntityReplacementText(String entityName, String replacementText)
+                throws XmlPullParserException {
+            parser.defineEntityReplacementText(entityName, replacementText);
+        }
+
+        @Override
+        public int getNamespaceCount(int depth) throws XmlPullParserException {
+            return parser.getNamespaceCount(depth);
+        }
+
+        @Override
+        public String getNamespacePrefix(int pos) throws XmlPullParserException {
+            return parser.getNamespacePrefix(pos);
+        }
+
+        @Override
+        public String getNamespaceUri(int pos) throws XmlPullParserException {
+            return parser.getNamespaceUri(pos);
+        }
+
+        @Override
+        public String getNamespace(String prefix) {
+            return parser.getNamespace(prefix);
+        }
+
+        @Override
+        public int getDepth() {
+            return parser.getDepth();
+        }
+
+        @Override
+        public String getPositionDescription() {
+            return parser.getPositionDescription();
+        }
+
+        @Override
+        public int getLineNumber() {
+            return parser.getLineNumber();
+        }
+
+        @Override
+        public int getColumnNumber() {
+            return parser.getColumnNumber();
+        }
+
+        @Override
+        public boolean isWhitespace() throws XmlPullParserException {
+            return parser.isWhitespace();
+        }
+
+        @Override
+        public String getText() {
+            return parser.getText();
+        }
+
+        @Override
+        public char[] getTextCharacters(int[] holderForStartAndLength) {
+            return parser.getTextCharacters(holderForStartAndLength);
+        }
+
+        @Override
+        public String getNamespace() {
+            return parser.getNamespace();
+        }
+
+        @Override
+        public String getName() {
+            return parser.getName();
+        }
+
+        @Override
+        public String getPrefix() {
+            return parser.getPrefix();
+        }
+
+        @Override
+        public boolean isEmptyElementTag() throws XmlPullParserException {
+            return false;
+        }
+
+        @Override
+        public int getAttributeCount() {
+            return parser.getAttributeCount();
+        }
+
+        public int next() throws IOException, XmlPullParserException {
+            return parser.next();
+        }
+
+        @Override
+        public int nextToken() throws XmlPullParserException, IOException {
+            return parser.next();
+        }
+
+        @Override
+        public void require(int type, String namespace, String name)
+                throws XmlPullParserException, IOException {
+            parser.require(type, namespace, name);
+        }
+
+        @Override
+        public String nextText() throws XmlPullParserException, IOException {
+            return parser.nextText();
+        }
+
+        @Override
+        public String getAttributeNamespace(int index) {
+            return "";
+        }
+
+        @Override
+        public String getAttributeName(int index) {
+            return parser.getAttributeName(index);
+        }
+
+        @Override
+        public String getAttributePrefix(int index) {
+            return parser.getAttributePrefix(index);
+        }
+
+        @Override
+        public String getAttributeType(int index) {
+            return parser.getAttributeType(index);
+        }
+
+        @Override
+        public boolean isAttributeDefault(int index) {
+            return parser.isAttributeDefault(index);
+        }
+
+        @Override
+        public String getAttributeValue(int index) {
+            return parser.getAttributeValue(index);
+        }
+
+        @Override
+        public String getAttributeValue(String namespace, String name) {
+            return parser.getAttributeValue(namespace, name);
+        }
+
+        @Override
+        public int getAttributeNameResource(int index) {
+            return 0;
+        }
+
+        @Override
+        public int getAttributeListValue(String namespace, String attribute, String[] options,
+                int defaultValue) {
+            return 0;
+        }
+
+        @Override
+        public boolean getAttributeBooleanValue(String namespace, String attribute,
+                boolean defaultValue) {
+            return false;
+        }
+
+        @Override
+        public int getAttributeResourceValue(String namespace, String attribute, int defaultValue) {
+            return 0;
+        }
+
+        @Override
+        public int getAttributeIntValue(String namespace, String attribute, int defaultValue) {
+            return 0;
+        }
+
+        @Override
+        public int getAttributeUnsignedIntValue(String namespace, String attribute,
+                int defaultValue) {
+            return 0;
+        }
+
+        @Override
+        public float getAttributeFloatValue(String namespace, String attribute,
+                float defaultValue) {
+            return 0;
+        }
+
+        @Override
+        public int getAttributeListValue(int index, String[] options, int defaultValue) {
+            return 0;
+        }
+
+        @Override
+        public boolean getAttributeBooleanValue(int index, boolean defaultValue) {
+            return false;
+        }
+
+        @Override
+        public int getAttributeResourceValue(int index, int defaultValue) {
+            return 0;
+        }
+
+        @Override
+        public int getAttributeIntValue(int index, int defaultValue) {
+            return 0;
+        }
+
+        @Override
+        public int getAttributeUnsignedIntValue(int index, int defaultValue) {
+            return 0;
+        }
+
+        @Override
+        public float getAttributeFloatValue(int index, float defaultValue) {
+            return 0;
+        }
+
+        @Override
+        public String getIdAttribute() {
+            return null;
+        }
+
+        @Override
+        public String getClassAttribute() {
+            return null;
+        }
+
+        @Override
+        public int getIdAttributeResourceValue(int defaultValue) {
+            return 0;
+        }
+
+        @Override
+        public int getStyleAttribute() {
+            return 0;
+        }
+
+        @Override
+        public void close() {
+        }
+
+        @Override
+        public int nextTag() throws IOException, XmlPullParserException {
+            return parser.nextTag();
+        }
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
new file mode 100644
index 0000000..7c6b1c1
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
@@ -0,0 +1,456 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distriZenbuted on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.notification;
+
+import static junit.framework.Assert.assertEquals;
+
+import android.service.notification.ZenPolicy;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.server.UiServiceTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ZenPolicyTest extends UiServiceTestCase {
+
+    @Test
+    public void testZenPolicyApplyAllowedToDisallowed() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        // reminders are disallowed
+        builder.allowReminders(false);
+        ZenPolicy remindersDisallowed = builder.build();
+        assertEquals(ZenPolicy.STATE_DISALLOW,
+                remindersDisallowed.getPriorityCategoryReminders());
+
+        // reminders are allowed
+        builder.allowReminders(true);
+        ZenPolicy remindersAllowed = builder.build();
+        assertEquals(ZenPolicy.STATE_ALLOW,
+                remindersAllowed.getPriorityCategoryReminders());
+        assertEquals(ZenPolicy.STATE_DISALLOW,
+                remindersDisallowed.getPriorityCategoryReminders());
+
+        // we apply reminders allowed to reminders disallowed
+        // -> reminders should remain disallowed
+        remindersDisallowed.apply(remindersAllowed);
+        assertEquals(ZenPolicy.STATE_DISALLOW,
+                remindersDisallowed.getPriorityCategoryReminders());
+    }
+
+    @Test
+    public void testZenPolicyApplyAllowedToUnset() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        // reminders are unset
+        ZenPolicy remindersUnset = builder.build();
+
+        // reminders are allowed
+        builder.allowReminders(true);
+        ZenPolicy remindersAllowed = builder.build();
+
+        // we apply reminders allowed to reminders unset
+        // -> reminders should be allowed
+        remindersUnset.apply(remindersAllowed);
+        assertEquals(ZenPolicy.STATE_ALLOW, remindersUnset.getPriorityCategoryReminders());
+    }
+
+    @Test
+    public void testZenPolicyApplyDisallowedToUnset() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        // reminders are unset
+        ZenPolicy remindersUnset = builder.build();
+
+        // reminders are disallowed
+        builder.allowReminders(false);
+        ZenPolicy remindersDisallowed = builder.build();
+
+        // we apply reminders disallowed to reminders unset
+        // -> reminders should remain disallowed
+        remindersUnset.apply(remindersDisallowed);
+        assertEquals(ZenPolicy.STATE_DISALLOW,
+                remindersUnset.getPriorityCategoryReminders());
+    }
+
+    @Test
+    public void testZenPolicyApplyDisallowedToAllowed() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        // reminders are allowed
+        builder.allowReminders(true);
+        ZenPolicy remindersAllowed = builder.build();
+
+        // reminders are disallowed
+        builder.allowReminders(false);
+        ZenPolicy remindersDisallowed = builder.build();
+
+        // we apply reminders allowed to reminders disallowed
+        // -> reminders should change to disallowed
+        remindersAllowed.apply(remindersDisallowed);
+        assertEquals(ZenPolicy.STATE_DISALLOW, remindersAllowed.getPriorityCategoryReminders());
+    }
+
+    @Test
+    public void testZenPolicyApplyUnsetToAllowed() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        // reminders are allowed
+        builder.allowReminders(true);
+        ZenPolicy remindersAllowed = builder.build();
+
+        // reminders are unset
+        ZenPolicy.Builder builder2 = new ZenPolicy.Builder();
+        ZenPolicy remindersUnset = builder2.build();
+
+        // we apply reminders allowed to reminders unset
+        // -> reminders should remain allowed
+        remindersAllowed.apply(remindersUnset);
+        assertEquals(ZenPolicy.STATE_ALLOW, remindersAllowed.getPriorityCategoryReminders());
+    }
+
+    @Test
+    public void testZenPolicyApplyMoreSevereCallSenders() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        // calls from contacts allowed
+        builder.allowCalls(ZenPolicy.PEOPLE_TYPE_CONTACTS);
+        ZenPolicy contactsAllowed = builder.build();
+
+        // calls from starred contacts allowed
+        builder.allowCalls(ZenPolicy.PEOPLE_TYPE_STARRED);
+        ZenPolicy starredAllowed = builder.build();
+
+        // we apply starredAllowed to contactsAllowed -> starred contacts allowed (more restrictive)
+        contactsAllowed.apply(starredAllowed);
+        assertEquals(ZenPolicy.STATE_ALLOW, contactsAllowed.getPriorityCategoryCalls());
+        assertEquals(ZenPolicy.PEOPLE_TYPE_STARRED, contactsAllowed.getPriorityCallSenders());
+    }
+
+    @Test
+    public void testZenPolicyApplyLessSevereCallSenders() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        // calls from contacts allowed
+        builder.allowCalls(ZenPolicy.PEOPLE_TYPE_CONTACTS);
+        ZenPolicy contactsAllowed = builder.build();
+
+        // calls from anyone allowed
+        builder.allowCalls(ZenPolicy.PEOPLE_TYPE_ANYONE);
+        ZenPolicy anyoneAllowed = builder.build();
+
+        // we apply anyoneAllowed to contactsAllowed -> contactsAllowed (more restrictive)
+        contactsAllowed.apply(anyoneAllowed);
+        assertEquals(ZenPolicy.STATE_ALLOW, contactsAllowed.getPriorityCategoryCalls());
+        assertEquals(ZenPolicy.PEOPLE_TYPE_CONTACTS, contactsAllowed.getPriorityCallSenders());
+    }
+
+    @Test
+    public void testZenPolicyApplyMoreSevereMessageSenders() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        // messsages from contacts allowed
+        builder.allowMessages(ZenPolicy.PEOPLE_TYPE_CONTACTS);
+        ZenPolicy contactsAllowed = builder.build();
+
+        // messsages from no one allowed
+        builder.allowMessages(ZenPolicy.PEOPLE_TYPE_NONE);
+        ZenPolicy noneAllowed = builder.build();
+
+        // noneAllowed to contactsAllowed -> no messages allowed (more restrictive)
+        contactsAllowed.apply(noneAllowed);
+        assertEquals(ZenPolicy.STATE_DISALLOW, contactsAllowed.getPriorityCategoryMessages());
+        assertEquals(ZenPolicy.PEOPLE_TYPE_NONE, contactsAllowed.getPriorityMessageSenders());
+    }
+
+    @Test
+    public void testZenPolicyMessagesInvalid() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        builder.allowMessages(20); // invalid #, won't change policy
+        ZenPolicy policy = builder.build();
+        assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategoryMessages());
+        assertEquals(ZenPolicy.PEOPLE_TYPE_UNSET, policy.getPriorityMessageSenders());
+    }
+
+    @Test
+    public void testZenPolicyCallsInvalid() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        builder.allowCalls(ZenPolicy.PEOPLE_TYPE_ANYONE);
+        builder.allowCalls(20); // invalid #, won't change policy
+        ZenPolicy policy = builder.build();
+        assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryCalls());
+        assertEquals(ZenPolicy.PEOPLE_TYPE_ANYONE, policy.getPriorityCallSenders());
+    }
+
+    @Test
+    public void testEmptyZenPolicy() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        ZenPolicy policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, -1);
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+    }
+
+    @Test
+    public void testAllowReminders() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        builder.allowReminders(true);
+        ZenPolicy policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_REMINDERS);
+        assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryReminders());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+
+        builder.allowReminders(false);
+        policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_REMINDERS);
+        assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryReminders());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+    }
+
+    @Test
+    public void testAllowEvents() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        builder.allowEvents(true);
+        ZenPolicy policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_EVENTS);
+        assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryEvents());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+
+        builder.allowEvents(false);
+        policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_EVENTS);
+        assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryEvents());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+    }
+
+    @Test
+    public void testAllowMessages() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        builder.allowMessages(ZenPolicy.PEOPLE_TYPE_ANYONE);
+        ZenPolicy policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_MESSAGES);
+        assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryMessages());
+        assertEquals(ZenPolicy.PEOPLE_TYPE_ANYONE, policy.getPriorityMessageSenders());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+
+        builder.allowMessages(ZenPolicy.PEOPLE_TYPE_CONTACTS);
+        policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_MESSAGES);
+        assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryMessages());
+        assertEquals(ZenPolicy.PEOPLE_TYPE_CONTACTS, policy.getPriorityMessageSenders());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+
+        builder.allowMessages(ZenPolicy.PEOPLE_TYPE_STARRED);
+        policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_MESSAGES);
+        assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryMessages());
+        assertEquals(ZenPolicy.PEOPLE_TYPE_STARRED, policy.getPriorityMessageSenders());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+
+        builder.allowMessages(ZenPolicy.PEOPLE_TYPE_NONE);
+        policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_MESSAGES);
+        assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryMessages());
+        assertEquals(ZenPolicy.PEOPLE_TYPE_NONE, policy.getPriorityMessageSenders());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+
+        builder.allowMessages(ZenPolicy.PEOPLE_TYPE_UNSET);
+        policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, -1);
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+    }
+
+    @Test
+    public void testAllowCalls() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        builder.allowCalls(ZenPolicy.PEOPLE_TYPE_ANYONE);
+        ZenPolicy policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_CALLS);
+        assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryCalls());
+        assertEquals(ZenPolicy.PEOPLE_TYPE_ANYONE, policy.getPriorityCallSenders());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+
+        builder.allowCalls(ZenPolicy.PEOPLE_TYPE_CONTACTS);
+        policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_CALLS);
+        assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryCalls());
+        assertEquals(ZenPolicy.PEOPLE_TYPE_CONTACTS, policy.getPriorityCallSenders());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+
+        builder.allowCalls(ZenPolicy.PEOPLE_TYPE_STARRED);
+        policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_CALLS);
+        assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryCalls());
+        assertEquals(ZenPolicy.PEOPLE_TYPE_STARRED, policy.getPriorityCallSenders());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+
+        builder.allowCalls(ZenPolicy.PEOPLE_TYPE_NONE);
+        policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_CALLS);
+        assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryCalls());
+        assertEquals(ZenPolicy.PEOPLE_TYPE_NONE, policy.getPriorityCallSenders());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+
+        builder.allowCalls(ZenPolicy.PEOPLE_TYPE_UNSET);
+        policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, -1);
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+    }
+
+    @Test
+    public void testAllowRepeatCallers() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        builder.allowRepeatCallers(true);
+        ZenPolicy policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_REPEAT_CALLERS);
+        assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryRepeatCallers());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+
+        builder.allowRepeatCallers(false);
+        policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_REPEAT_CALLERS);
+        assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryRepeatCallers());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+    }
+
+    @Test
+    public void testAllowAlarms() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        builder.allowAlarms(true);
+        ZenPolicy policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_ALARMS);
+        assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryAlarms());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+
+        builder.allowAlarms(false);
+        policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_ALARMS);
+        assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryAlarms());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+    }
+
+    @Test
+    public void testAllowMedia() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        builder.allowMedia(true);
+        ZenPolicy policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_MEDIA);
+        assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryMedia());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+
+        builder.allowMedia(false);
+        policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_MEDIA);
+        assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryMedia());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+    }
+
+    @Test
+    public void testAllowSystem() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        builder.allowSystem(true);
+        ZenPolicy policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_SYSTEM);
+        assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategorySystem());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+
+        builder.allowSystem(false);
+        policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_SYSTEM);
+        assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategorySystem());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+    }
+
+    private void assertAllPriorityCategoriesUnsetExcept(ZenPolicy policy, int except) {
+        if (except != ZenPolicy.PRIORITY_CATEGORY_REMINDERS) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategoryReminders());
+        }
+
+        if (except != ZenPolicy.PRIORITY_CATEGORY_EVENTS) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategoryEvents());
+        }
+
+        if (except != ZenPolicy.PRIORITY_CATEGORY_MESSAGES) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategoryMessages());
+        }
+
+        if (except != ZenPolicy.PRIORITY_CATEGORY_CALLS) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategoryCalls());
+        }
+
+        if (except != ZenPolicy.PRIORITY_CATEGORY_REPEAT_CALLERS) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategoryRepeatCallers());
+        }
+
+        if (except != ZenPolicy.PRIORITY_CATEGORY_ALARMS) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategoryAlarms());
+        }
+
+        if (except != ZenPolicy.PRIORITY_CATEGORY_MEDIA) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategoryMedia());
+        }
+
+        if (except != ZenPolicy.PRIORITY_CATEGORY_SYSTEM) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategorySystem());
+        }
+    }
+
+    private void assertAllVisualEffectsUnsetExcept(ZenPolicy policy, int except) {
+        if (except != ZenPolicy.VISUAL_EFFECT_FULL_SCREEN_INTENT) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getVisualEffectFullScreenIntent());
+        }
+
+        if (except != ZenPolicy.VISUAL_EFFECT_LIGHTS) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getVisualEffectLights());
+        }
+
+        if (except != ZenPolicy.VISUAL_EFFECT_PEEK) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getVisualEffectPeek());
+        }
+
+        if (except != ZenPolicy.VISUAL_EFFECT_STATUS_BAR) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getVisualEffectStatusBar());
+        }
+
+        if (except != ZenPolicy.VISUAL_EFFECT_BADGE) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getVisualEffectBadge());
+        }
+
+        if (except != ZenPolicy.VISUAL_EFFECT_AMBIENT) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getVisualEffectAmbient());
+        }
+
+        if (except != ZenPolicy.VISUAL_EFFECT_NOTIFICATION_LIST) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getVisualEffectNotificationList());
+        }
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/policy/DummyPolicyTests.java b/services/tests/wmtests/src/com/android/server/policy/DummyPolicyTests.java
new file mode 100644
index 0000000..03fb123
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/policy/DummyPolicyTests.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.policy;
+
+import android.platform.test.annotations.Presubmit;
+
+import org.junit.Test;
+
+import androidx.test.filters.FlakyTest;
+
+/**
+ * Dummy test for com.android.server.policy.
+ * TODO(b/113800711): Remove this class once the actual tests are moved from servicestests.
+ */
+public class DummyPolicyTests {
+
+    @Presubmit
+    @Test
+    public void preSubmitTest() {}
+
+    @FlakyTest
+    @Presubmit
+    @Test
+    public void flakyPreSubmitTest() {}
+
+    @Test
+    public void postSubmitTest() {}
+
+    @FlakyTest
+    @Test
+    public void flakyPostSubmitTest() {}
+}
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 589bcdc..cf47ad3 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -40,6 +40,7 @@
 import com.android.server.usb.descriptors.UsbDescriptor;
 import com.android.server.usb.descriptors.UsbDescriptorParser;
 import com.android.server.usb.descriptors.UsbDeviceDescriptor;
+import com.android.server.usb.descriptors.UsbInterfaceDescriptor;
 import com.android.server.usb.descriptors.report.TextReportCanvas;
 import com.android.server.usb.descriptors.tree.UsbDescriptorsTree;
 
@@ -352,8 +353,6 @@
             }
             return false;
         }
-        UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress, descriptors);
-        logUsbDevice(parser);
 
         if (isBlackListed(deviceClass, deviceSubclass)) {
             if (DEBUG) {
@@ -362,6 +361,15 @@
             return false;
         }
 
+        UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress, descriptors);
+        if (deviceClass == UsbConstants.USB_CLASS_PER_INTERFACE
+                && !checkUsbInterfacesBlackListed(parser)) {
+            return false;
+        }
+
+        // Potentially can block as it may read data from the USB device.
+        logUsbDevice(parser);
+
         synchronized (mLock) {
             if (mDevices.get(deviceAddress) != null) {
                 Slog.w(TAG, "device already on mDevices list: " + deviceAddress);
@@ -513,6 +521,29 @@
         }
     }
 
+    private boolean checkUsbInterfacesBlackListed(UsbDescriptorParser parser) {
+        // Device class needs to be obtained through the device interface.  Ignore device only
+        // if ALL interfaces are black-listed.
+        boolean shouldIgnoreDevice = false;
+        for (UsbDescriptor descriptor: parser.getDescriptors()) {
+            if (!(descriptor instanceof UsbInterfaceDescriptor)) {
+                continue;
+            }
+            UsbInterfaceDescriptor iface = (UsbInterfaceDescriptor) descriptor;
+            shouldIgnoreDevice = isBlackListed(iface.getUsbClass(), iface.getUsbSubclass());
+            if (!shouldIgnoreDevice) {
+                break;
+            }
+        }
+        if (shouldIgnoreDevice) {
+            if (DEBUG) {
+                Slog.d(TAG, "usb interface class is black listed");
+            }
+            return false;
+        }
+        return true;
+    }
+
     private native void monitorUsbHostBus();
     private native ParcelFileDescriptor nativeOpenDevice(String deviceAddress);
 }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index c5d6dc7..99ad1f4 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -19,6 +19,8 @@
 import android.Manifest;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
+
+import com.android.internal.app.IVoiceActionCheckCallback;
 import com.android.server.wm.ActivityTaskManagerInternal;
 import android.app.AppGlobals;
 import android.content.ComponentName;
@@ -1128,6 +1130,27 @@
             }
         }
 
+        @Override
+        public void getActiveServiceSupportedActions(List<String> voiceActions,
+                IVoiceActionCheckCallback callback) {
+            enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
+            synchronized (this) {
+                if (mImpl == null) {
+                    try {
+                        callback.onComplete(null);
+                    } catch (RemoteException e) {
+                    }
+                    return;
+                }
+                final long caller = Binder.clearCallingIdentity();
+                try {
+                    mImpl.getActiveServiceSupportedActions(voiceActions, callback);
+                } finally {
+                    Binder.restoreCallingIdentity(caller);
+                }
+            }
+        }
+
         public void onSessionShown() {
             synchronized (this) {
                 final int size = mVoiceInteractionSessionListeners.beginBroadcast();
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 57e9f66..61d7d6c 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -25,6 +25,8 @@
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
+
+import com.android.internal.app.IVoiceActionCheckCallback;
 import com.android.server.wm.ActivityTaskManagerInternal;
 import android.app.IActivityManager;
 import android.app.IActivityTaskManager;
@@ -57,6 +59,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
 
 class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConnection.Callback {
     final static String TAG = "VoiceInteractionServiceManager";
@@ -177,6 +180,23 @@
                 activityTokens);
     }
 
+    public void getActiveServiceSupportedActions(List<String> commands,
+            IVoiceActionCheckCallback callback) {
+        if (mService == null) {
+            Slog.w(TAG, "Not bound to voice interaction service " + mComponent);
+            try {
+                callback.onComplete(null);
+            } catch (RemoteException e) {
+            }
+            return;
+        }
+        try {
+            mService.getActiveServiceSupportedActions(commands, callback);
+        } catch (RemoteException e) {
+            Slog.w(TAG, "RemoteException while calling getActiveServiceSupportedActions", e);
+        }
+    }
+
     public boolean hideSessionLocked() {
         if (mActiveSession != null) {
             return mActiveSession.hideLocked();
diff --git a/startop/scripts/app_startup/force_compiler_filter b/startop/scripts/app_startup/force_compiler_filter
new file mode 100755
index 0000000..08f983d
--- /dev/null
+++ b/startop/scripts/app_startup/force_compiler_filter
@@ -0,0 +1,143 @@
+#!/bin/bash
+#
+# Copyright 2018, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Forces an application APK to be compiled (by ART's dex2oat)
+# with a specific compiler filter.
+#
+# Example usage:
+#    $> ./force_compiler_filter -p com.google.android.apps.maps -c speed-profile
+#
+# (The application may be started/stopped as a side effect)
+#
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+source "$DIR/lib/common"
+
+usage() {
+    cat <<EOF
+Usage: $(basename $0) [OPTION]...
+
+  Required:
+    -p, --package               package of the app to recompile
+    -c, --compiler-filter       override the compiler filter if set (default none)
+                                valid options are listed by: adb shell cmd package, under compile -m
+
+  Optional:
+    -a, --activity              activity of the app to recompile
+    -h, --help                  usage information (this)
+    -v, --verbose               enable extra verbose printing
+    -w, --wait_time             how long to wait for app startup (default 10) in seconds
+EOF
+}
+
+wait_time="10" # seconds
+
+parse_arguments() {
+  while [[ $# -gt 0 ]]; do
+    case "$1" in
+      -a|--activity)
+        activity="$2"
+        shift
+        ;;
+      -h|--help)
+        usage
+        exit 0
+        ;;
+      -p|--package)
+        package="$2"
+        shift
+        ;;
+      -w|--wait_time)
+        wait_time="$2"
+        shift
+        ;;
+      -c|--compiler-filter)
+        compiler_filter="$2"
+        shift
+        ;;
+      -v|--verbose)
+        verbose="y"
+        ;;
+    esac
+    shift
+  done
+
+  if [[ -z "$compiler_filter" ]]; then
+    echo "Missing required --compiler-filter" >&2
+    echo ""
+    usage
+    exit 1
+  fi
+  if [[ -z "$package" ]]; then
+    echo "Missing required --package" >&2
+    echo ""
+    usage
+    exit 1
+  fi
+
+  if [[ "$activity" == "" ]]; then
+    activity="$(get_activity_name "$package")"
+    if [[ "$activity" == "" ]]; then
+      echo "Activity name could not be found, invalid package name?" 1>&2
+      exit 1
+    else
+      verbose_print "Activity name inferred: " "$activity"
+    fi
+  fi
+}
+
+force_package_compilation() {
+  local arg_compiler_filter="$1"
+  local arg_package="$2"
+
+  if [[ $arg_compiler_filter == speed-profile ]]; then
+    # Force the running app to dump its profiles to disk.
+    remote_pkill "$arg_package" -SIGUSR1
+    sleep 1 # give some time for above to complete.
+  fi
+
+  adb shell cmd package compile -m "$arg_compiler_filter" -f "$arg_package"
+}
+
+main() {
+  parse_arguments "$@"
+
+  if [[ $compiler_filter == speed-profile ]]; then
+    # screen needs to be unlocked in order to run an app
+    "$DIR"/unlock_screen
+
+    local output=$("$DIR"/launch_application "$package" "$activity")
+    if [[ $? -ne 0 ]]; then
+      echo "launching application failed" >&2
+      exit 1
+    fi
+
+    verbose_print "$output"
+    # give some time for app startup to complete.
+    # this is supposed to be an upper bound for measuring startup time.
+    sleep "$wait_time"
+  fi
+
+  force_package_compilation "$compiler_filter" "$package"
+
+  # kill the application to ensure next time it's started,
+  # it picks up the correct compilation filter.
+  adb shell am force-stop "$package"
+  remote_pkill "$package"
+}
+
+main "$@"
diff --git a/startop/scripts/app_startup/launch_application b/startop/scripts/app_startup/launch_application
index bc4ec51..8a68e50 100755
--- a/startop/scripts/app_startup/launch_application
+++ b/startop/scripts/app_startup/launch_application
@@ -20,6 +20,12 @@
 launch_application() {
   local package="$1"
   local activity="$2"
+
+  # if there's any $s inside of the activity name, it needs to be escaped to \$.
+  # example '.app.honeycomb.Shell$HomeActivity'
+  # if the $ is not escaped, adb shell will try to evaluate $HomeActivity to a variable.
+  activity=${activity//\$/\\$}
+
   local am_output="$(adb shell am start -S -W "$package"/"$activity")"
   verbose_print adb shell am start -S -W "$package"/"$activity"
   if [[ $? -ne 0 ]]; then
diff --git a/startop/scripts/app_startup/lib/common b/startop/scripts/app_startup/lib/common
index 4d5a53e..043d855 100755
--- a/startop/scripts/app_startup/lib/common
+++ b/startop/scripts/app_startup/lib/common
@@ -12,3 +12,42 @@
     echo "$@" >&2
   fi
 }
+
+remote_pidof() {
+  local procname="$1"
+  adb shell ps | grep "$procname" | awk '{print $2;}'
+}
+
+remote_pkill() {
+  local procname="$1"
+  shift
+
+  local the_pids=$(remote_pidof "$procname")
+  local pid
+
+  for pid in $the_pids; do
+    verbose_print adb shell kill "$@" "$pid"
+    adb shell kill "$@" "$pid"
+  done
+}
+
+get_activity_name() {
+  local package="$1"
+  local action_key="android.intent.action.MAIN:"
+
+  # Example query-activities output being parsed:
+  #
+  #  Activity #14:
+  #    priority=0 preferredOrder=0 match=0x108000 specificIndex=-1 isDefault=true
+  #    com.google.android.videos/com.google.android.youtube.videos.EntryPoint
+  #  Activity #15:
+  #    priority=0 preferredOrder=0 match=0x108000 specificIndex=-1 isDefault=true
+  #    com.google.android.youtube/.app.honeycomb.Shell$HomeActivity
+
+  # Given package 'com.google.android.youtube' return '.app.honeycomb.Shell$HomeActivity'
+
+  local activity_line="$(adb shell cmd package query-activities --brief -a android.intent.action.MAIN -c android.intent.category.LAUNCHER | grep "$package/")"
+  IFS="/" read -a array <<< "$activity_line"
+  local activity_name="${array[1]}"
+  echo "$activity_name"
+}
diff --git a/startop/scripts/app_startup/query_compiler_filter.py b/startop/scripts/app_startup/query_compiler_filter.py
new file mode 100755
index 0000000..dc97c66
--- /dev/null
+++ b/startop/scripts/app_startup/query_compiler_filter.py
@@ -0,0 +1,226 @@
+#!/usr/bin/env python3
+#
+# Copyright 2018, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+#
+# Query the current compiler filter for an application by its package name.
+# (By parsing the results of the 'adb shell dumpsys package $package' command).
+# The output is a string "$compilation_filter $compilation_reason $isa".
+#
+# See --help for more details.
+#
+# -----------------------------------
+#
+# Sample usage:
+#
+# $> ./query_compiler_filter.py --package com.google.android.calculator
+# speed-profile unknown arm64
+#
+
+import argparse
+import sys
+import re
+
+# TODO: refactor this with a common library file with analyze_metrics.py
+import app_startup_runner
+from app_startup_runner import _debug_print
+from app_startup_runner import execute_arbitrary_command
+
+from typing import List, NamedTuple, Iterable
+
+_DEBUG_FORCE = None  # Ignore -d/--debug if this is not none.
+
+def parse_options(argv: List[str] = None):
+  """Parse command line arguments and return an argparse Namespace object."""
+  parser = argparse.ArgumentParser(description="Query the compiler filter for a package.")
+  # argparse considers args starting with - and -- optional in --help, even though required=True.
+  # by using a named argument group --help will clearly say that it's required instead of optional.
+  required_named = parser.add_argument_group('required named arguments')
+  required_named.add_argument('-p', '--package', action='store', dest='package', help='package of the application', required=True)
+
+  # optional arguments
+  # use a group here to get the required arguments to appear 'above' the optional arguments in help.
+  optional_named = parser.add_argument_group('optional named arguments')
+  optional_named.add_argument('-i', '--isa', '--instruction-set', action='store', dest='instruction_set', help='which instruction set to select. defaults to the first one available if not specified.', choices=('arm64', 'arm', 'x86_64', 'x86'))
+  optional_named.add_argument('-s', '--simulate', dest='simulate', action='store_true', help='Print which commands will run, but don\'t run the apps')
+  optional_named.add_argument('-d', '--debug', dest='debug', action='store_true', help='Add extra debugging output')
+
+  return parser.parse_args(argv)
+
+def remote_dumpsys_package(package: str, simulate: bool) -> str:
+  # --simulate is used for interactive debugging/development, but also for the unit test.
+  if simulate:
+    return """
+Dexopt state:
+  [%s]
+    path: /data/app/%s-D7s8PLidqqEq7Jc7UH_a5A==/base.apk
+      arm64: [status=speed-profile] [reason=unknown]
+    path: /data/app/%s-D7s8PLidqqEq7Jc7UH_a5A==/base.apk
+      arm: [status=speed] [reason=first-boot]
+    path: /data/app/%s-D7s8PLidqqEq7Jc7UH_a5A==/base.apk
+      x86: [status=quicken] [reason=install]
+""" %(package, package, package, package)
+
+  code, res = execute_arbitrary_command(['adb', 'shell', 'dumpsys', 'package', package], simulate=False, timeout=5)
+  if code:
+    return res
+  else:
+    raise AssertionError("Failed to dumpsys package, errors = %s", res)
+
+ParseTree = NamedTuple('ParseTree', [('label', str), ('children', List['ParseTree'])])
+DexoptState = ParseTree # With the Dexopt state: label
+ParseResult = NamedTuple('ParseResult', [('remainder', List[str]), ('tree', ParseTree)])
+
+def find_parse_subtree(parse_tree: ParseTree, match_regex: str) -> ParseTree:
+  if re.match(match_regex, parse_tree.label):
+    return parse_tree
+
+  for node in parse_tree.children:
+    res = find_parse_subtree(node, match_regex)
+    if res:
+      return res
+
+  return None
+
+def find_parse_children(parse_tree: ParseTree, match_regex: str) -> Iterable[ParseTree]:
+  for node in parse_tree.children:
+    if re.match(match_regex, node.label):
+      yield node
+
+def parse_tab_subtree(label: str, str_lines: List[str], separator=' ', indent=-1) -> ParseResult:
+  children = []
+
+  get_indent_level = lambda line: len(line) - len(line.lstrip())
+
+  line_num = 0
+
+  keep_going = True
+  while keep_going:
+    keep_going = False
+
+    for line_num in range(len(str_lines)):
+      line = str_lines[line_num]
+      current_indent = get_indent_level(line)
+
+      _debug_print("INDENT=%d, LINE=%s" %(current_indent, line))
+
+      current_label = line.lstrip()
+
+      # skip empty lines
+      if line.lstrip() == "":
+        continue
+
+      if current_indent > indent:
+        parse_result = parse_tab_subtree(current_label, str_lines[line_num+1::], separator, current_indent)
+        str_lines = parse_result.remainder
+        children.append(parse_result.tree)
+        keep_going = True
+      else:
+        # current_indent <= indent
+        keep_going = False
+
+      break
+
+  new_remainder = str_lines[line_num::]
+  _debug_print("NEW REMAINDER: ", new_remainder)
+
+  parse_tree = ParseTree(label, children)
+  return ParseResult(new_remainder, parse_tree)
+
+def parse_tab_tree(str_tree: str, separator=' ', indentation_level=-1) -> ParseTree:
+
+  label = None
+  lst = []
+
+  line_num = 0
+  line_lst = str_tree.split("\n")
+
+  return parse_tab_subtree("", line_lst, separator, indentation_level).tree
+
+def parse_dexopt_state(dumpsys_tree: ParseTree) -> DexoptState:
+  res = find_parse_subtree(dumpsys_tree, "Dexopt(\s+)state[:]?")
+  if not res:
+    raise AssertionError("Could not find the Dexopt state")
+  return res
+
+def find_first_compiler_filter(dexopt_state: DexoptState, package: str, instruction_set: str) -> str:
+  lst = find_all_compiler_filters(dexopt_state, package)
+
+  _debug_print("all compiler filters: ", lst)
+
+  for compiler_filter_info in lst:
+    if not instruction_set:
+      return compiler_filter_info
+
+    if compiler_filter_info.isa == instruction_set:
+      return compiler_filter_info
+
+  return None
+
+CompilerFilterInfo = NamedTuple('CompilerFilterInfo', [('isa', str), ('status', str), ('reason', str)])
+
+def find_all_compiler_filters(dexopt_state: DexoptState, package: str) -> List[CompilerFilterInfo]:
+
+  lst = []
+  package_tree = find_parse_subtree(dexopt_state, re.escape("[%s]" %package))
+
+  if not package_tree:
+    raise AssertionError("Could not find any package subtree for package %s" %(package))
+
+  _debug_print("package tree: ", package_tree)
+
+  for path_tree in find_parse_children(package_tree, "path: "):
+    _debug_print("path tree: ", path_tree)
+
+    matchre = re.compile("([^:]+):\s+\[status=([^\]]+)\]\s+\[reason=([^\]]+)\]")
+
+    for isa_node in find_parse_children(path_tree, matchre):
+
+      matches = re.match(matchre, isa_node.label).groups()
+
+      info = CompilerFilterInfo(*matches)
+      lst.append(info)
+
+  return lst
+
+def main() -> int:
+  opts = parse_options()
+  app_startup_runner._debug = opts.debug
+  if _DEBUG_FORCE is not None:
+    app_startup_runner._debug = _DEBUG_FORCE
+  _debug_print("parsed options: ", opts)
+
+  # Note: This can often 'fail' if the package isn't actually installed.
+  package_dumpsys = remote_dumpsys_package(opts.package, opts.simulate)
+  _debug_print("package dumpsys: ", package_dumpsys)
+  dumpsys_parse_tree = parse_tab_tree(package_dumpsys, package_dumpsys)
+  _debug_print("parse tree: ", dumpsys_parse_tree)
+  dexopt_state = parse_dexopt_state(dumpsys_parse_tree)
+
+  filter = find_first_compiler_filter(dexopt_state, opts.package, opts.instruction_set)
+
+  if filter:
+    print(filter.status, end=' ')
+    print(filter.reason, end=' ')
+    print(filter.isa)
+  else:
+    print("ERROR: Could not find any compiler-filter for package %s, isa %s" %(opts.package, opts.instruction_set), file=sys.stderr)
+    return 1
+
+  return 0
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/startop/scripts/app_startup/query_compiler_filter_test.py b/startop/scripts/app_startup/query_compiler_filter_test.py
new file mode 100755
index 0000000..a751a43
--- /dev/null
+++ b/startop/scripts/app_startup/query_compiler_filter_test.py
@@ -0,0 +1,116 @@
+#!/usr/bin/env python3
+#
+# Copyright 2018, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""
+Unit tests for the query_compiler_filter.py script.
+
+Install:
+  $> sudo apt-get install python3-pytest   ##  OR
+  $> pip install -U pytest
+See also https://docs.pytest.org/en/latest/getting-started.html
+
+Usage:
+  $> ./query_compiler_filter.py
+  $> pytest query_compiler_filter.py
+  $> python -m pytest query_compiler_filter.py
+
+See also https://docs.pytest.org/en/latest/usage.html
+"""
+
+# global imports
+from contextlib import contextmanager
+import io
+import shlex
+import sys
+import typing
+
+# pip imports
+import pytest
+
+# local imports
+import query_compiler_filter as qcf
+
+@contextmanager
+def redirect_stdout_stderr():
+  """Redirect stdout/stderr to a new StringIO for duration of context."""
+  old_stdout = sys.stdout
+  old_stderr = sys.stderr
+  new_stdout = io.StringIO()
+  sys.stdout = new_stdout
+  new_stderr = io.StringIO()
+  sys.stderr = new_stderr
+  try:
+    yield (new_stdout, new_stderr)
+  finally:
+    sys.stdout = old_stdout
+    sys.stderr = old_stderr
+    # Seek back to the beginning so we can read whatever was written into it.
+    new_stdout.seek(0)
+    new_stderr.seek(0)
+
+@contextmanager
+def replace_argv(argv):
+  """ Temporarily replace argv for duration of this context."""
+  old_argv = sys.argv
+  sys.argv = [sys.argv[0]] + argv
+  try:
+    yield
+  finally:
+    sys.argv = old_argv
+
+def exec_main(argv):
+  """Run the query_compiler_filter main function with the provided arguments.
+
+  Returns the stdout result when successful, assertion failure otherwise.
+  """
+  try:
+    with redirect_stdout_stderr() as (the_stdout, the_stderr):
+      with replace_argv(argv):
+        code = qcf.main()
+    assert 0 == code, the_stderr.readlines()
+
+    all_lines = the_stdout.readlines()
+    return "".join(all_lines)
+  finally:
+    the_stdout.close()
+    the_stderr.close()
+
+def test_query_compiler_filter():
+  # no --instruction-set specified: provide whatever was the 'first' filter.
+  assert exec_main(['--simulate',
+                    '--package', 'com.google.android.apps.maps']) == \
+      "speed-profile unknown arm64\n"
+
+  # specifying an instruction set finds the exact compiler filter match.
+  assert exec_main(['--simulate',
+                    '--package', 'com.google.android.apps.maps',
+                    '--instruction-set', 'arm64']) == \
+      "speed-profile unknown arm64\n"
+
+  assert exec_main(['--simulate',
+                    '--package', 'com.google.android.apps.maps',
+                    '--instruction-set', 'arm']) == \
+      "speed first-boot arm\n"
+
+  assert exec_main(['--simulate',
+                    '--debug',
+                    '--package', 'com.google.android.apps.maps',
+                    '--instruction-set', 'x86']) == \
+      "quicken install x86\n"
+
+if __name__ == '__main__':
+  pytest.main()
diff --git a/startop/scripts/app_startup/run_app_with_prefetch b/startop/scripts/app_startup/run_app_with_prefetch
index 1ff5fc6..56bffa8 100755
--- a/startop/scripts/app_startup/run_app_with_prefetch
+++ b/startop/scripts/app_startup/run_app_with_prefetch
@@ -92,8 +92,7 @@
         shift
         ;;
       --compiler-filter)
-        # ignore any '--compiler-filter xyz' settings.
-        # FIXME: app_startup_runner.py should not be passing this flag.
+        compiler_filter="$2"
         shift
         ;;
       *)
@@ -112,18 +111,6 @@
   echo "$@"
 }
 
-get_activity_name() {
-  local package="$1"
-  local action_key="android.intent.action.MAIN:"
-
-  local activity_line="$(adb shell cmd package query-activities --brief -a android.intent.action.MAIN -c android.intent.category.LAUNCHER | grep "$package")"
-  #echo $activity_line
-  IFS="/" read -a array <<< "$activity_line"
-  local activity_name="${array[1]}"
-  echo "$activity_name"
-  #adb shell am start "$package/$activity_name"
-}
-
 find_package_path() {
   local pkg="$1"
 
@@ -134,11 +121,6 @@
   echo "$res"
 }
 
-remote_pkill() {
-  local what="$1"
-  adb shell "for i in $(pid $what); do kill \$i; done"
-}
-
 # Main entry point
 if [[ $# -eq 0 ]]; then
   usage
@@ -194,9 +176,6 @@
 fi
 verbose_print "Package was in path '$package_path'"
 
-
-
-
 keep_application_trace_file=n
 application_trace_file_path="$package_path/TraceFile.pb"
 trace_file_directory="$package_path"
@@ -286,6 +265,47 @@
   fi
 }
 
+configure_compiler_filter() {
+  local the_compiler_filter="$1"
+  local the_package="$2"
+  local the_activity="$3"
+
+  if [[ -z $the_compiler_filter ]]; then
+    verbose_print "No --compiler-filter specified, don't need to force it."
+    return 0
+  fi
+
+  local current_compiler_filter_info="$("$DIR"/query_compiler_filter.py --package "$the_package")"
+  local res=$?
+  if [[ $res -ne 0 ]]; then
+    return $res
+  fi
+
+  local current_compiler_filter
+  local current_reason
+  local current_isa
+  read current_compiler_filter current_reason current_isa <<< "$current_compiler_filter_info"
+
+  verbose_print "Compiler Filter="$current_compiler_filter "Reason="$current_reason "Isa="$current_isa
+
+  # Don't trust reasons that aren't 'unknown' because that means we didn't manually force the compilation filter.
+  # (e.g. if any automatic system-triggered compilations are not unknown).
+  if [[ $current_reason != "unknown" ]] || [[ $current_compiler_filter != $the_compiler_filter ]]; then
+    verbose_print "$DIR"/force_compiler_filter --compiler-filter "$the_compiler_filter" --package "$the_package" --activity "$the_activity"
+    "$DIR"/force_compiler_filter --compiler-filter "$the_compiler_filter" --package "$the_package" --activity "$the_activity"
+    res=$?
+  else
+    verbose_print "Queried compiler-filter matched requested compiler-filter, skip forcing."
+    res=0
+  fi
+
+  return $res
+}
+
+# Ensure the APK is currently compiled with whatever we passed in via --compiler-filter.
+# No-op if this option was not passed in.
+configure_compiler_filter "$compiler_filter" "$package" "$activity" || exit 1
+
 # TODO: This loop logic could probably be moved into app_startup_runner.py
 for ((i=0;i<count;++i)) do
   verbose_print "=========================================="
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 096cf37..08bc9bc 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -141,6 +141,8 @@
      * The caller must specify the {@link #EXTRA_HANDOVER_PHONE_ACCOUNT_HANDLE} to indicate to
      * Telecom which {@link PhoneAccountHandle} the {@link Call} should be handed over to.
      * @hide
+     * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+     * APIs instead.
      */
     public static final String EVENT_REQUEST_HANDOVER =
             "android.telecom.event.REQUEST_HANDOVER";
@@ -149,6 +151,8 @@
      * Extra key used with the {@link #EVENT_REQUEST_HANDOVER} call event.  Specifies the
      * {@link PhoneAccountHandle} to which a call should be handed over to.
      * @hide
+     * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+     * APIs instead.
      */
     public static final String EXTRA_HANDOVER_PHONE_ACCOUNT_HANDLE =
             "android.telecom.extra.HANDOVER_PHONE_ACCOUNT_HANDLE";
@@ -161,6 +165,8 @@
      * {@link VideoProfile#STATE_BIDIRECTIONAL}, {@link VideoProfile#STATE_RX_ENABLED}, and
      * {@link VideoProfile#STATE_TX_ENABLED}.
      * @hide
+     * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+     * APIs instead.
      */
     public static final String EXTRA_HANDOVER_VIDEO_STATE =
             "android.telecom.extra.HANDOVER_VIDEO_STATE";
@@ -176,6 +182,8 @@
      * {@link ConnectionService#onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}
      * is called to initate the handover.
      * @hide
+     * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+     * APIs instead.
      */
     public static final String EXTRA_HANDOVER_EXTRAS = "android.telecom.extra.HANDOVER_EXTRAS";
 
@@ -186,6 +194,8 @@
      * <p>
      * A handover is initiated with the {@link #EVENT_REQUEST_HANDOVER} call event.
      * @hide
+     * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+     * APIs instead.
      */
     public static final String EVENT_HANDOVER_COMPLETE =
             "android.telecom.event.HANDOVER_COMPLETE";
@@ -198,6 +208,8 @@
      * <p>
      * A handover is initiated with the {@link #EVENT_REQUEST_HANDOVER} call event.
      * @hide
+     * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+     * APIs instead.
      */
     public static final String EVENT_HANDOVER_SOURCE_DISCONNECTED =
             "android.telecom.event.HANDOVER_SOURCE_DISCONNECTED";
@@ -209,6 +221,8 @@
      * <p>
      * A handover is initiated with the {@link #EVENT_REQUEST_HANDOVER} call event.
      * @hide
+     * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+     * APIs instead.
      */
     public static final String EVENT_HANDOVER_FAILED =
             "android.telecom.event.HANDOVER_FAILED";
@@ -434,8 +448,15 @@
          */
         public static final int PROPERTY_RTT = 0x00000400;
 
+        /**
+         * Indicates that the call has been identified as the network as an emergency call. This
+         * property may be set for both incoming and outgoing calls which the network identifies as
+         * emergency calls.
+         */
+        public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 0x00000800;
+
         //******************************************************************************************
-        // Next PROPERTY value: 0x00000800
+        // Next PROPERTY value: 0x00001000
         //******************************************************************************************
 
         private final String mTelecomCallId;
@@ -601,6 +622,9 @@
             if(hasProperty(properties, PROPERTY_ASSISTED_DIALING_USED)) {
                 builder.append(" PROPERTY_ASSISTED_DIALING_USED");
             }
+            if (hasProperty(properties, PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL)) {
+                builder.append(" PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL");
+            }
             builder.append("]");
             return builder.toString();
         }
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index 024bd30..a39e885 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -22,6 +22,8 @@
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.telecom.Connection.VideoProvider;
+import android.telephony.ServiceState;
+import android.telephony.TelephonyManager;
 import android.util.ArraySet;
 
 import java.util.ArrayList;
@@ -573,6 +575,20 @@
     }
 
     /**
+     * Updates RIL voice radio technology used for current conference after its creation.
+     *
+     * @hide
+     */
+    public void updateCallRadioTechAfterCreation() {
+        final Connection primaryConnection = getPrimaryConnection();
+        if (primaryConnection != null) {
+            setCallRadioTech(primaryConnection.getCallRadioTech());
+        } else {
+            Log.w(this, "No primary connection found while updateCallRadioTechAfterCreation");
+        }
+    }
+
+    /**
      * @hide
      * @deprecated Use {@link #setConnectionTime}.
      */
@@ -652,6 +668,37 @@
     }
 
     /**
+     * Sets RIL voice radio technology used for current conference.
+     *
+     * @param vrat the RIL voice radio technology used for current conference,
+     *             see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
+     *
+     * @hide
+     */
+    public final void setCallRadioTech(@ServiceState.RilRadioTechnology int vrat) {
+        putExtra(TelecomManager.EXTRA_CALL_NETWORK_TYPE,
+                ServiceState.rilRadioTechnologyToNetworkType(vrat));
+    }
+
+    /**
+     * Returns RIL voice radio technology used for current conference.
+     *
+     * @return the RIL voice radio technology used for current conference,
+     *         see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
+     *
+     * @hide
+     */
+    public final @ServiceState.RilRadioTechnology int getCallRadioTech() {
+        int voiceNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+        Bundle extras = getExtras();
+        if (extras != null) {
+            voiceNetworkType = extras.getInt(TelecomManager.EXTRA_CALL_NETWORK_TYPE,
+                    TelephonyManager.NETWORK_TYPE_UNKNOWN);
+        }
+        return ServiceState.networkTypeToRilRadioTechnology(voiceNetworkType);
+    }
+
+    /**
      * Inform this Conference that the state of its audio output has been changed externally.
      *
      * @param state The new audio state.
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 3d2b397..34603a3 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -38,6 +38,8 @@
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.telephony.ServiceState;
+import android.telephony.TelephonyManager;
 import android.util.ArraySet;
 import android.view.Surface;
 
@@ -412,6 +414,13 @@
      */
     public static final int PROPERTY_ASSISTED_DIALING_USED = 1 << 9;
 
+    /**
+     * Set by the framework to indicate that the network has identified a Connection as an emergency
+     * call.
+     * @hide
+     */
+    public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 1 << 10;
+
     //**********************************************************************************************
     // Next PROPERTY value: 1<<10
     //**********************************************************************************************
@@ -585,6 +594,8 @@
      * {@link Call#EVENT_REQUEST_HANDOVER} that the handover from this {@link Connection} has
      * successfully completed.
      * @hide
+     * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+     * APIs instead.
      */
     public static final String EVENT_HANDOVER_COMPLETE =
             "android.telecom.event.HANDOVER_COMPLETE";
@@ -594,6 +605,8 @@
      * {@link Call#EVENT_REQUEST_HANDOVER} that the handover from this {@link Connection} has failed
      * to complete.
      * @hide
+     * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+     * APIs instead.
      */
     public static final String EVENT_HANDOVER_FAILED =
             "android.telecom.event.HANDOVER_FAILED";
@@ -801,6 +814,10 @@
             builder.append(isLong ? " PROPERTY_IS_RTT" : " rtt");
         }
 
+        if (can(properties, PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL)) {
+            builder.append(isLong ? " PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL" : " ecall");
+        }
+
         builder.append("]");
         return builder.toString();
     }
@@ -1885,6 +1902,24 @@
     }
 
     /**
+     * Returns RIL voice radio technology used for current connection.
+     *
+     * @return the RIL voice radio technology used for current connection,
+     *         see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
+     *
+     * @hide
+     */
+    public final @ServiceState.RilRadioTechnology int getCallRadioTech() {
+        int voiceNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+        Bundle extras = getExtras();
+        if (extras != null) {
+            voiceNetworkType = extras.getInt(TelecomManager.EXTRA_CALL_NETWORK_TYPE,
+                    TelephonyManager.NETWORK_TYPE_UNKNOWN);
+        }
+        return ServiceState.networkTypeToRilRadioTechnology(voiceNetworkType);
+    }
+
+    /**
      * @return The status hints for this connection.
      */
     public final StatusHints getStatusHints() {
@@ -2318,6 +2353,26 @@
     }
 
     /**
+     * Sets RIL voice radio technology used for current connection.
+     *
+     * @param vrat the RIL Voice Radio Technology used for current connection,
+     *             see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
+     *
+     * @hide
+     */
+    public final void setCallRadioTech(@ServiceState.RilRadioTechnology int vrat) {
+        putExtra(TelecomManager.EXTRA_CALL_NETWORK_TYPE,
+                ServiceState.rilRadioTechnologyToNetworkType(vrat));
+        // Propagates the call radio technology to its parent {@link android.telecom.Conference}
+        // This action only covers non-IMS CS conference calls.
+        // For IMS PS call conference call, it can be updated via its host connection
+        // {@link #Listener.onExtrasChanged} event.
+        if (getConference() != null) {
+            getConference().setCallRadioTech(vrat);
+        }
+    }
+
+    /**
      * Sets the label and icon status to display in the in-call UI.
      *
      * @param statusHints The status label and icon to set.
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index 8b0211e..3ad0f0c 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -18,6 +18,7 @@
 
 import android.annotation.UnsupportedAppUsage;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -118,7 +119,7 @@
     }
 
     /** The unique ID of the call. */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public String getId() {
         return mId;
     }
diff --git a/telecomm/java/android/telecom/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java
index 279804e..097e352 100644
--- a/telecomm/java/android/telecom/PhoneAccountHandle.java
+++ b/telecomm/java/android/telecom/PhoneAccountHandle.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.Process;
@@ -43,7 +44,7 @@
 public final class PhoneAccountHandle implements Parcelable {
     @UnsupportedAppUsage
     private final ComponentName mComponentName;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final String mId;
     private final UserHandle mUserHandle;
 
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 4e22823..8c37a21 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -317,6 +317,15 @@
             "android.telecom.extra.CALL_TECHNOLOGY_TYPE";
 
     /**
+     * Optional extra for communicating the call network technology used by a
+     * {@link android.telecom.Connection} to Telecom and InCallUI.
+     *
+     * @see {@code NETWORK_TYPE_*} in {@link android.telephony.TelephonyManager}.
+     */
+    public static final String EXTRA_CALL_NETWORK_TYPE =
+            "android.telecom.extra.CALL_NETWORK_TYPE";
+
+    /**
      * An optional {@link android.content.Intent#ACTION_CALL} intent extra denoting the
      * package name of the app specifying an alternative gateway for the call.
      * The value is a string.
@@ -1875,6 +1884,27 @@
         }
     }
 
+    /**
+     * Determines if there is an ongoing emergency call.  This can be either an outgoing emergency
+     * call, as identified by the dialed number, or because a call was identified by the network
+     * as an emergency call.
+     * @return {@code true} if there is an ongoing emergency call, {@code false} otherwise.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    public boolean isInEmergencyCall() {
+        try {
+            if (isServiceConnected()) {
+                return getTelecomService().isInEmergencyCall();
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException isInEmergencyCall: " + e);
+            return false;
+        }
+        return false;
+    }
+
     private ITelecomService getTelecomService() {
         if (mTelecomServiceOverride != null) {
             return mTelecomServiceOverride;
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index b4e7d56..38247bc 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -279,4 +279,9 @@
      * @see TelecomServiceImpl#acceptHandover
      */
     void acceptHandover(in Uri srcAddr, int videoState, in PhoneAccountHandle destAcct);
+
+    /**
+     * @see TelecomServiceImpl#isInEmergencyCall
+     */
+    boolean isInEmergencyCall();
 }
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index ed84788..4846092 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -30,6 +30,7 @@
 import android.database.Cursor;
 import android.database.sqlite.SqliteWrapper;
 import android.net.Uri;
+import android.os.Build;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SmsMessage;
@@ -374,7 +375,7 @@
          * Return cursor for table query.
          * @hide
          */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public static Cursor query(ContentResolver cr, String[] projection,
                 String where, String orderBy) {
             return cr.query(CONTENT_URI, projection, where,
@@ -1232,6 +1233,17 @@
                           "android.provider.action.EXTERNAL_PROVIDER_CHANGE";
 
             /**
+             * Same as {@link #ACTION_DEFAULT_SMS_PACKAGE_CHANGED} but it's implicit (e.g. sent to
+             * all apps) and requires
+             * {@link android.Manifest.permission#MONITOR_DEFAULT_SMS_PACKAGE} to receive.
+             *
+             * @hide
+             */
+            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+            public static final String ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL =
+                    "android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL";
+
+            /**
              * Read the PDUs out of an {@link #SMS_RECEIVED_ACTION} or a
              * {@link #DATA_SMS_RECEIVED_ACTION} intent.
              *
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index ffbe7d3..995418e 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1070,6 +1070,16 @@
 
     /**
      * Indexes of SPN format strings in wfcSpnFormats and wfcDataSpnFormats.
+     *
+     * <p>Available options are:
+     * <ul>
+     * <li> 0: %s</li>
+     * <li> 1: %s Wi-Fi Calling</li>
+     * <li> 2: WLAN Call</li>
+     * <li> 3: %s WLAN Call</li>
+     * <li> 4: %s Wi-Fi</li>
+     * <li> 5: WiFi Calling | %s</li>
+     * <li> 6: %s VoWifi</li>
      * @hide
      */
     public static final String KEY_WFC_SPN_FORMAT_IDX_INT = "wfc_spn_format_idx_int";
@@ -1077,6 +1087,15 @@
     public static final String KEY_WFC_DATA_SPN_FORMAT_IDX_INT = "wfc_data_spn_format_idx_int";
 
     /**
+     * Use root locale when reading wfcSpnFormats.
+     *
+     * If true, then the root locale will always be used when reading wfcSpnFormats. This means the
+     * non localized version of wfcSpnFormats will be used.
+     * @hide
+     */
+    public static final String KEY_WFC_SPN_USE_ROOT_LOCALE = "wfc_spn_use_root_locale";
+
+    /**
      * The Component Name of the activity that can setup the emergency addrees for WiFi Calling
      * as per carrier requirement.
      * @hide
@@ -1947,6 +1966,17 @@
             "skip_cf_fail_to_disable_dialog_bool";
 
     /**
+     * Flag specifying whether operator supports including no reply condition timer option on
+     * CFNRy (3GPP TS 24.082 3: Call Forwarding on No Reply) in the call forwarding settings UI.
+     * {@code true}  - include no reply condition timer option on CFNRy
+     * {@code false} - don't include no reply condition timer option on CFNRy
+     *
+     * @hide
+     */
+    public static final String KEY_SUPPORT_NO_REPLY_TIMER_FOR_CFNRY_BOOL =
+            "support_no_reply_timer_for_cfnry_bool";
+
+    /**
      * List of the FAC (feature access codes) to dial as a normal call.
      * @hide
      */
@@ -2085,6 +2115,16 @@
     public static final String KEY_CONFIG_SHOW_ORIG_DIAL_STRING_FOR_CDMA_BOOL =
             "config_show_orig_dial_string_for_cdma";
 
+    /**
+     * Flag specifying whether to show notification(call blocking disabled) when Enhanced Call
+     * Blocking(KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL) is enabled and making emergency call.
+     * When true, notification is shown always.
+     * When false, notification is shown only when any setting of "Enhanced Blocked number" is
+     * enabled.
+     */
+    public static final String KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL =
+            "show_call_blocking_disabled_notification_always_bool";
+
     /** The default value for every variable. */
     private final static PersistableBundle sDefaults;
 
@@ -2263,6 +2303,7 @@
         sDefaults.putStringArray(KEY_WFC_OPERATOR_ERROR_CODES_STRING_ARRAY, null);
         sDefaults.putInt(KEY_WFC_SPN_FORMAT_IDX_INT, 0);
         sDefaults.putInt(KEY_WFC_DATA_SPN_FORMAT_IDX_INT, 0);
+        sDefaults.putBoolean(KEY_WFC_SPN_USE_ROOT_LOCALE, false);
         sDefaults.putString(KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING, "");
         sDefaults.putBoolean(KEY_CONFIG_WIFI_DISABLE_IN_ECBM, false);
         sDefaults.putBoolean(KEY_CARRIER_NAME_OVERRIDE_BOOL, false);
@@ -2272,7 +2313,7 @@
         sDefaults.putBoolean(KEY_SUPPORT_DIRECT_FDN_DIALING_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_DEFAULT_DATA_ROAMING_ENABLED_BOOL, false);
         sDefaults.putBoolean(KEY_SKIP_CF_FAIL_TO_DISABLE_DIALOG_BOOL, false);
-        sDefaults.putBoolean(KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL, false);
+        sDefaults.putBoolean(KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL, true);
 
         // MMS defaults
         sDefaults.putBoolean(KEY_MMS_ALIAS_ENABLED_BOOL, false);
@@ -2398,6 +2439,7 @@
         sDefaults.putBoolean(KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, false);
         sDefaults.putBoolean(KEY_RTT_SUPPORTED_BOOL, false);
         sDefaults.putBoolean(KEY_DISABLE_CHARGE_INDICATION_BOOL, false);
+        sDefaults.putBoolean(KEY_SUPPORT_NO_REPLY_TIMER_FOR_CFNRY_BOOL, true);
         sDefaults.putStringArray(KEY_FEATURE_ACCESS_CODES_STRING_ARRAY, null);
         sDefaults.putBoolean(KEY_IDENTIFY_HIGH_DEFINITION_CALLS_IN_CALL_LOG_BOOL, false);
         sDefaults.putBoolean(KEY_SHOW_PRECISE_FAILED_CAUSE_BOOL, false);
@@ -2421,6 +2463,7 @@
                 });
         sDefaults.putString(KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING, "");
         sDefaults.putBoolean(KEY_CONFIG_SHOW_ORIG_DIAL_STRING_FOR_CDMA_BOOL, false);
+        sDefaults.putBoolean(KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL, false);
     }
 
     /**
diff --git a/telephony/java/android/telephony/MbmsGroupCallSession.java b/telephony/java/android/telephony/MbmsGroupCallSession.java
new file mode 100644
index 0000000..e373797
--- /dev/null
+++ b/telephony/java/android/telephony/MbmsGroupCallSession.java
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.telephony.mbms.GroupCall;
+import android.telephony.mbms.GroupCallCallback;
+import android.telephony.mbms.InternalGroupCallCallback;
+import android.telephony.mbms.InternalGroupCallSessionCallback;
+import android.telephony.mbms.MbmsErrors;
+import android.telephony.mbms.MbmsGroupCallSessionCallback;
+import android.telephony.mbms.MbmsUtils;
+import android.telephony.mbms.vendor.IMbmsGroupCallService;
+import android.util.ArraySet;
+import android.util.Log;
+
+import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * This class provides functionality for accessing group call functionality over MBMS.
+ */
+public class MbmsGroupCallSession implements AutoCloseable {
+    private static final String LOG_TAG = "MbmsGroupCallSession";
+
+    /**
+     * Service action which must be handled by the middleware implementing the MBMS group call
+     * interface.
+     * @hide
+     */
+    @SystemApi
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String MBMS_GROUP_CALL_SERVICE_ACTION =
+            "android.telephony.action.EmbmsGroupCall";
+
+    /**
+     * Metadata key that specifies the component name of the service to bind to for group calls.
+     * @hide
+     */
+    @TestApi
+    public static final String MBMS_GROUP_CALL_SERVICE_OVERRIDE_METADATA =
+            "mbms-group-call-service-override";
+
+    private static AtomicBoolean sIsInitialized = new AtomicBoolean(false);
+
+    private AtomicReference<IMbmsGroupCallService> mService = new AtomicReference<>(null);
+    private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
+        @Override
+        public void binderDied() {
+            sIsInitialized.set(false);
+            mInternalCallback.onError(MbmsErrors.ERROR_MIDDLEWARE_LOST,
+                    "Received death notification");
+        }
+    };
+
+    private InternalGroupCallSessionCallback mInternalCallback;
+    private Set<GroupCall> mKnownActiveGroupCalls = new ArraySet<>();
+
+    private final Context mContext;
+    private int mSubscriptionId;
+
+    /** @hide */
+    private MbmsGroupCallSession(Context context, Executor executor, int subscriptionId,
+            MbmsGroupCallSessionCallback callback) {
+        mContext = context;
+        mSubscriptionId = subscriptionId;
+        mInternalCallback = new InternalGroupCallSessionCallback(callback, executor);
+    }
+
+    /**
+     * Create a new {@link MbmsGroupCallSession} using the given subscription ID.
+     *
+     * You may only have one instance of {@link MbmsGroupCallSession} per UID. If you call this
+     * method while there is an active instance of {@link MbmsGroupCallSession} in your process
+     * (in other words, one that has not had {@link #close()} called on it), this method will
+     * throw an {@link IllegalStateException}. If you call this method in a different process
+     * running under the same UID, an error will be indicated via
+     * {@link MbmsGroupCallSessionCallback#onError(int, String)}.
+     *
+     * Note that initialization may fail asynchronously. If you wish to try again after you
+     * receive such an asynchronous error, you must call {@link #close()} on the instance of
+     * {@link MbmsGroupCallSession} that you received before calling this method again.
+     *
+     * @param context The {@link Context} to use.
+     * @param executor The executor on which you wish to execute callbacks.
+     * @param subscriptionId The subscription ID to use.
+     * @param callback A callback object on which you wish to receive results of asynchronous
+     *                 operations.
+     * @return An instance of {@link MbmsGroupCallSession}, or null if an error occurred.
+     */
+    public static @Nullable MbmsGroupCallSession create(@NonNull Context context,
+            @NonNull Executor executor, int subscriptionId,
+            final @NonNull MbmsGroupCallSessionCallback callback) {
+        if (!sIsInitialized.compareAndSet(false, true)) {
+            throw new IllegalStateException("Cannot create two instances of MbmsGroupCallSession");
+        }
+        MbmsGroupCallSession session = new MbmsGroupCallSession(context, executor,
+                subscriptionId, callback);
+
+        final int result = session.bindAndInitialize();
+        if (result != MbmsErrors.SUCCESS) {
+            sIsInitialized.set(false);
+            executor.execute(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onError(result, null);
+                }
+            });
+            return null;
+        }
+        return session;
+    }
+
+    /**
+     * Create a new {@link MbmsGroupCallSession} using the system default data subscription ID.
+     * See {@link #create(Context, Executor, int, MbmsGroupCallSessionCallback)}.
+     */
+    public static MbmsGroupCallSession create(@NonNull Context context,
+            @NonNull Executor executor, @NonNull MbmsGroupCallSessionCallback callback) {
+        return create(context, executor, SubscriptionManager.getDefaultSubscriptionId(), callback);
+    }
+
+    /**
+     * Terminates this instance. Also terminates
+     * any group calls spawned from this instance as if
+     * {@link GroupCall#close()} had been called on them. After this method returns,
+     * no further callbacks originating from the middleware will be enqueued on the provided
+     * instance of {@link MbmsGroupCallSessionCallback}, but callbacks that have already been
+     * enqueued will still be delivered.
+     *
+     * It is safe to call {@link #create(Context, Executor, int, MbmsGroupCallSessionCallback)} to
+     * obtain another instance of {@link MbmsGroupCallSession} immediately after this method
+     * returns.
+     *
+     * May throw an {@link IllegalStateException}
+     */
+    public void close() {
+        try {
+            IMbmsGroupCallService groupCallService = mService.get();
+            if (groupCallService == null) {
+                // Ignore and return, assume already disposed.
+                return;
+            }
+            groupCallService.dispose(mSubscriptionId);
+            for (GroupCall s : mKnownActiveGroupCalls) {
+                s.getCallback().stop();
+            }
+            mKnownActiveGroupCalls.clear();
+        } catch (RemoteException e) {
+            // Ignore for now
+        } finally {
+            mService.set(null);
+            sIsInitialized.set(false);
+            mInternalCallback.stop();
+        }
+    }
+
+    /**
+     * Starts the requested group call, reporting status to the indicated callback.
+     * Returns an object used to control that call.
+     *
+     * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
+     *
+     * Asynchronous errors through the callback include any of the errors in
+     * {@link MbmsErrors.GeneralErrors}.
+     *
+     * @param executor The executor on which you wish to execute callbacks for this stream.
+     * @param tmgi The TMGI, an identifier for the group call you want to join.
+     * @param saiArray An array of SAIs for the group call that should be negotiated separately with
+     *                the carrier.
+     * @param frequencyArray An array of frequencies for the group call that should be negotiated
+     *                separately with the carrier.
+     * @param callback The callback that you want to receive information about the call on.
+     * @return An instance of {@link GroupCall} through which the call can be controlled.
+     *         May be {@code null} if an error occurred.
+     */
+    public @Nullable GroupCall startGroupCall(@NonNull Executor executor, long tmgi, int[] saiArray,
+            int[] frequencyArray, @NonNull GroupCallCallback callback) {
+        IMbmsGroupCallService groupCallService = mService.get();
+        if (groupCallService == null) {
+            throw new IllegalStateException("Middleware not yet bound");
+        }
+
+        InternalGroupCallCallback serviceCallback = new InternalGroupCallCallback(
+                callback, executor);
+
+        GroupCall serviceForApp = new GroupCall(mSubscriptionId,
+                groupCallService, this, tmgi, serviceCallback);
+        mKnownActiveGroupCalls.add(serviceForApp);
+
+        try {
+            int returnCode = groupCallService.startGroupCall(
+                    mSubscriptionId, tmgi, saiArray, frequencyArray, serviceCallback);
+            if (returnCode == MbmsErrors.UNKNOWN) {
+                // Unbind and throw an obvious error
+                close();
+                throw new IllegalStateException("Middleware must not return an unknown error code");
+            }
+            if (returnCode != MbmsErrors.SUCCESS) {
+                mInternalCallback.onError(returnCode, null);
+                return null;
+            }
+        } catch (RemoteException e) {
+            Log.w(LOG_TAG, "Remote process died");
+            mService.set(null);
+            sIsInitialized.set(false);
+            mInternalCallback.onError(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
+            return null;
+        }
+
+        return serviceForApp;
+    }
+
+    /** @hide */
+    public void onGroupCallStopped(GroupCall service) {
+        mKnownActiveGroupCalls.remove(service);
+    }
+
+    private int bindAndInitialize() {
+        return MbmsUtils.startBinding(mContext, MBMS_GROUP_CALL_SERVICE_ACTION,
+                new ServiceConnection() {
+                    @Override
+                    public void onServiceConnected(ComponentName name, IBinder service) {
+                        IMbmsGroupCallService groupCallService =
+                                IMbmsGroupCallService.Stub.asInterface(service);
+                        int result;
+                        try {
+                            result = groupCallService.initialize(mInternalCallback,
+                                    mSubscriptionId);
+                        } catch (RemoteException e) {
+                            Log.e(LOG_TAG, "Service died before initialization");
+                            mInternalCallback.onError(
+                                    MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
+                                    e.toString());
+                            sIsInitialized.set(false);
+                            return;
+                        } catch (RuntimeException e) {
+                            Log.e(LOG_TAG, "Runtime exception during initialization");
+                            mInternalCallback.onError(
+                                    MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
+                                    e.toString());
+                            sIsInitialized.set(false);
+                            return;
+                        }
+                        if (result == MbmsErrors.UNKNOWN) {
+                            // Unbind and throw an obvious error
+                            close();
+                            throw new IllegalStateException("Middleware must not return"
+                                    + " an unknown error code");
+                        }
+                        if (result != MbmsErrors.SUCCESS) {
+                            mInternalCallback.onError(result,
+                                    "Error returned during initialization");
+                            sIsInitialized.set(false);
+                            return;
+                        }
+                        try {
+                            groupCallService.asBinder().linkToDeath(mDeathRecipient, 0);
+                        } catch (RemoteException e) {
+                            mInternalCallback.onError(MbmsErrors.ERROR_MIDDLEWARE_LOST,
+                                    "Middleware lost during initialization");
+                            sIsInitialized.set(false);
+                            return;
+                        }
+                        mService.set(groupCallService);
+                    }
+
+                    @Override
+                    public void onServiceDisconnected(ComponentName name) {
+                        sIsInitialized.set(false);
+                        mService.set(null);
+                    }
+                });
+    }
+}
diff --git a/telephony/java/android/telephony/NetworkScan.java b/telephony/java/android/telephony/NetworkScan.java
index 7c7d7a0..202da68 100644
--- a/telephony/java/android/telephony/NetworkScan.java
+++ b/telephony/java/android/telephony/NetworkScan.java
@@ -16,11 +16,10 @@
 
 package android.telephony;
 
+import android.annotation.IntDef;
 import android.content.Context;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.annotation.IntDef;
-import android.util.Log;
 
 import com.android.internal.telephony.ITelephony;
 
@@ -113,6 +112,8 @@
         }
         try {
             telephony.stopNetworkScan(mSubId, mScanId);
+        } catch (IllegalArgumentException ex) {
+            Rlog.d(TAG,  "stopNetworkScan - no active scan for ScanID=" + mScanId);
         } catch (RemoteException ex) {
             Rlog.e(TAG, "stopNetworkScan  RemoteException", ex);
         } catch (RuntimeException ex) {
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index 91e24a9..e40bae1 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -603,7 +603,7 @@
 
     /**
      * Returns the message body as a String, if it exists and is text based.
-     * @return message body is there is one, otherwise null
+     * @return message body if there is one, otherwise null
      */
     public String getMessageBody() {
         return mWrappedSmsMessage.getMessageBody();
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index ec26622..22c1e58 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -33,11 +33,13 @@
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.TextUtils;
 import android.util.DisplayMetrics;
 import android.util.Log;
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * A Parcelable class for Subscription Information.
@@ -552,11 +554,49 @@
         String cardIdToPrint = givePrintableIccid(mCardId);
         return "{id=" + mId + ", iccId=" + iccIdToPrint + " simSlotIndex=" + mSimSlotIndex
                 + " displayName=" + mDisplayName + " carrierName=" + mCarrierName
-                + " nameSource=" + mNameSource + " iconTint=" + mIconTint
+                + " nameSource=" + mNameSource + " iconTint=" + mIconTint + " mNumber=" + mNumber
                 + " dataRoaming=" + mDataRoaming + " iconBitmap=" + mIconBitmap + " mcc " + mMcc
-                + " mnc " + mMnc + " isEmbedded " + mIsEmbedded
+                + " mnc " + mMnc + "mCountryIso=" + mCountryIso + " isEmbedded " + mIsEmbedded
                 + " accessRules " + Arrays.toString(mAccessRules)
                 + " cardId=" + cardIdToPrint + " isOpportunistic " + mIsOpportunistic
                 + " parentSubId=" + mParentSubId + "}";
     }
-}
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mId, mSimSlotIndex, mNameSource, mIconTint, mDataRoaming, mIsEmbedded,
+                mIsOpportunistic, mParentSubId, mIccId, mNumber, mMcc, mMnc, mCountryIso,
+                mCardId, mDisplayName, mCarrierName, mAccessRules);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) return false;
+        if (obj == this) return true;
+
+        SubscriptionInfo toCompare;
+        try {
+            toCompare = (SubscriptionInfo) obj;
+        } catch (ClassCastException ex) {
+            return false;
+        }
+
+        return mId == toCompare.mId
+                && mSimSlotIndex == toCompare.mSimSlotIndex
+                && mNameSource == toCompare.mNameSource
+                && mIconTint == toCompare.mIconTint
+                && mDataRoaming == toCompare.mDataRoaming
+                && mIsEmbedded == toCompare.mIsEmbedded
+                && mIsOpportunistic == toCompare.mIsOpportunistic
+                && mParentSubId == toCompare.mParentSubId
+                && Objects.equals(mIccId, toCompare.mIccId)
+                && Objects.equals(mNumber, toCompare.mNumber)
+                && Objects.equals(mMcc, toCompare.mMcc)
+                && Objects.equals(mMnc, toCompare.mMnc)
+                && Objects.equals(mCountryIso, toCompare.mCountryIso)
+                && Objects.equals(mCardId, toCompare.mCardId)
+                && TextUtils.equals(mDisplayName, toCompare.mDisplayName)
+                && TextUtils.equals(mCarrierName, toCompare.mCarrierName)
+                && Arrays.equals(mAccessRules, toCompare.mAccessRules);
+    }
+}
\ No newline at end of file
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 8ebfec4..38ee79f 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -41,6 +41,7 @@
 import android.net.INetworkPolicyManager;
 import android.net.NetworkCapabilities;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -59,6 +60,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Locale;
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
 
@@ -84,9 +86,8 @@
     /** @hide */
     public static final int INVALID_PHONE_INDEX = -1;
 
-    /** An invalid slot identifier */
-    /** @hide */
-    public static final int INVALID_SIM_SLOT_INDEX = -1;
+    /** Indicates invalid sim slot. This can be returned by {@link #getSlotIndex(int)}. */
+    public static final int INVALID_SIM_SLOT_INDEX = -2;
 
     /** Indicates the caller wants the default sub id. */
     /** @hide */
@@ -137,9 +138,8 @@
     /** @hide */
     public static final String SIM_SLOT_INDEX = "sim_id";
 
-    /** SIM is not inserted */
-    /** @hide */
-    public static final int SIM_NOT_INSERTED = -1;
+    /** Indicates SIM is not inserted. This can be returned by {@link #getSlotIndex(int)}. */
+    public static final int SIM_NOT_INSERTED = -3;
 
     /**
      * TelephonyProvider column name for user displayed name.
@@ -191,7 +191,7 @@
      * The name_source is from the user
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public static final int NAME_SOURCE_USER_INPUT = 2;
 
     /**
@@ -1262,16 +1262,22 @@
 
     /**
      * Get slotIndex associated with the subscription.
-     * @return slotIndex as a positive integer or a negative value if an error either
-     * SIM_NOT_INSERTED or < 0 if an invalid slot index
-     * @hide
+     *
+     * @param subscriptionId the unique SubscriptionInfo index in database
+     * @return slotIndex as a positive integer or a negative value,
+     * <ol>
+     * <li>{@link #INVALID_SUBSCRIPTION_ID} if the supplied subscriptionId is invalid </li>
+     * <li>{@link #SIM_NOT_INSERTED} if sim is not inserted </li>
+     * <li>{@link #INVALID_SIM_SLOT_INDEX} if the supplied subscriptionId doesn't have an
+     *     associated slot index </li>
+     * </ol>
      */
-    @UnsupportedAppUsage
-    public static int getSlotIndex(int subId) {
-        if (!isValidSubscriptionId(subId)) {
+    public static int getSlotIndex(int subscriptionId) {
+        if (!isValidSubscriptionId(subscriptionId)) {
             if (DBG) {
-                logd("[getSlotIndex]- fail");
+                logd("[getSlotIndex]- supplied subscriptionId is invalid. ");
             }
+            return INVALID_SUBSCRIPTION_ID;
         }
 
         int result = INVALID_SIM_SLOT_INDEX;
@@ -1279,7 +1285,7 @@
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
-                result = iSub.getSlotIndex(subId);
+                result = iSub.getSlotIndex(subscriptionId);
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -1610,7 +1616,7 @@
     }
 
     /** @hide */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public static boolean isValidSlotIndex(int slotIndex) {
         return slotIndex >= 0 && slotIndex < TelephonyManager.getDefault().getSimCount();
     }
@@ -1810,6 +1816,19 @@
      */
     @UnsupportedAppUsage
     public static Resources getResourcesForSubId(Context context, int subId) {
+        return getResourcesForSubId(context, subId, false);
+    }
+
+    /**
+     * Returns the resources associated with Subscription.
+     * @param context Context object
+     * @param subId Subscription Id of Subscription who's resources are required
+     * @param useRootLocale if root locale should be used. Localized locale is used if false.
+     * @return Resources associated with Subscription.
+     * @hide
+     */
+    public static Resources getResourcesForSubId(Context context, int subId,
+            boolean useRootLocale) {
         final SubscriptionInfo subInfo =
                 SubscriptionManager.from(context).getActiveSubscriptionInfo(subId);
 
@@ -1821,6 +1840,11 @@
             newConfig.mnc = subInfo.getMnc();
             if (newConfig.mnc == 0) newConfig.mnc = Configuration.MNC_ZERO;
         }
+
+        if (useRootLocale) {
+            newConfig.setLocale(Locale.ROOT);
+        }
+
         DisplayMetrics metrics = context.getResources().getDisplayMetrics();
         DisplayMetrics newMetrics = new DisplayMetrics();
         newMetrics.setTo(metrics);
@@ -1828,6 +1852,19 @@
     }
 
     /**
+     * Checks if the supplied subscription ID corresponds to an active subscription.
+     *
+     * @param subscriptionId the subscription ID.
+     * @return {@code true} if the supplied subscription ID corresponds to an active subscription;
+     * {@code false} if it does not correspond to an active subscription; or throw a
+     * SecurityException if the caller hasn't got the right permission.
+     */
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    public boolean isActiveSubscriptionId(int subscriptionId) {
+        return isActiveSubId(subscriptionId);
+    }
+
+    /**
      * @return true if the sub ID is active. i.e. The sub ID corresponds to a known subscription
      * and the SIM providing the subscription is present in a slot and in "LOADED" state.
      * @hide
@@ -1837,7 +1874,7 @@
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
-                return iSub.isActiveSubId(subId);
+                return iSub.isActiveSubId(subId, mContext.getOpPackageName());
             }
         } catch (RemoteException ex) {
         }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 2ac0afe..824533d 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -16,6 +16,8 @@
 
 package android.telephony;
 
+import static android.content.Context.TELECOM_SERVICE;
+
 import static com.android.internal.util.Preconditions.checkNotNull;
 
 import android.annotation.IntDef;
@@ -39,6 +41,7 @@
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.BatteryStats;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.PersistableBundle;
@@ -68,6 +71,7 @@
 import com.android.internal.telephony.IPhoneSubInfo;
 import com.android.internal.telephony.ITelephony;
 import com.android.internal.telephony.ITelephonyRegistry;
+import com.android.internal.telephony.OperatorInfo;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.RILConstants;
 import com.android.internal.telephony.TelephonyProperties;
@@ -702,7 +706,7 @@
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     @Deprecated
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public static final String ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED =
             "android.intent.action.PRECISE_DATA_CONNECTION_STATE_CHANGED";
 
@@ -1199,6 +1203,15 @@
             "android.intent.action.DATA_STALL_DETECTED";
 
     /**
+     * A service action that identifies a {@link android.app.SmsAppService} subclass in the
+     * AndroidManifest.xml.
+     *
+     * <p>See {@link android.app.SmsAppService} for the details.
+     */
+    @SdkConstant(SdkConstantType.SERVICE_ACTION)
+    public static final String ACTION_SMS_APP_SERVICE = "android.telephony.action.SMS_APP_SERVICE";
+
+    /**
      * An int extra used with {@link #ACTION_DATA_STALL_DETECTED} to indicate the
      * action associated with the data stall recovery.
      *
@@ -1499,23 +1512,24 @@
                 Rlog.d(TAG, "getCellLocation returning null because telephony is null");
                 return null;
             }
+
             Bundle bundle = telephony.getCellLocation(mContext.getOpPackageName());
-            if (bundle.isEmpty()) {
-                Rlog.d(TAG, "getCellLocation returning null because bundle is empty");
+            if (bundle == null || bundle.isEmpty()) {
+                Rlog.d(TAG, "getCellLocation returning null because CellLocation is unavailable");
                 return null;
             }
+
             CellLocation cl = CellLocation.newFromBundle(bundle);
-            if (cl.isEmpty()) {
-                Rlog.d(TAG, "getCellLocation returning null because CellLocation is empty");
+            if (cl == null || cl.isEmpty()) {
+                Rlog.d(TAG, "getCellLocation returning null because CellLocation is empty or"
+                        + " phone type doesn't match CellLocation type");
                 return null;
             }
+
             return cl;
         } catch (RemoteException ex) {
             Rlog.d(TAG, "getCellLocation returning null due to RemoteException " + ex);
             return null;
-        } catch (NullPointerException ex) {
-            Rlog.d(TAG, "getCellLocation returning null due to NullPointerException " + ex);
-            return null;
         }
     }
 
@@ -1690,7 +1704,7 @@
     }
 
     /** {@hide} */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private int getPhoneTypeFromProperty(int phoneId) {
         String type = getTelephonyProperty(phoneId,
                 TelephonyProperties.CURRENT_ACTIVE_PHONE, null);
@@ -2088,10 +2102,37 @@
 
     /** Max network type number. Update as new types are added. Don't add negative types. {@hide} */
     public static final int MAX_NETWORK_TYPE = NETWORK_TYPE_LTE_CA;
+
+    /** @hide */
+    @IntDef({
+            NETWORK_TYPE_UNKNOWN,
+            NETWORK_TYPE_GPRS,
+            NETWORK_TYPE_EDGE,
+            NETWORK_TYPE_UMTS,
+            NETWORK_TYPE_CDMA,
+            NETWORK_TYPE_EVDO_0,
+            NETWORK_TYPE_EVDO_A,
+            NETWORK_TYPE_1xRTT,
+            NETWORK_TYPE_HSDPA,
+            NETWORK_TYPE_HSUPA,
+            NETWORK_TYPE_HSPA,
+            NETWORK_TYPE_IDEN,
+            NETWORK_TYPE_EVDO_B,
+            NETWORK_TYPE_LTE,
+            NETWORK_TYPE_EHRPD,
+            NETWORK_TYPE_HSPAP,
+            NETWORK_TYPE_GSM,
+            NETWORK_TYPE_TD_SCDMA,
+            NETWORK_TYPE_IWLAN,
+            NETWORK_TYPE_LTE_CA,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface NetworkType{}
+
     /**
      * @return the NETWORK_TYPE_xxxx for current data connection.
      */
-    public int getNetworkType() {
+    public @NetworkType int getNetworkType() {
        try {
            ITelephony telephony = getITelephony();
            if (telephony != null) {
@@ -2136,24 +2177,24 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
-   @UnsupportedAppUsage
-   public int getNetworkType(int subId) {
-       try {
-           ITelephony telephony = getITelephony();
-           if (telephony != null) {
-               return telephony.getNetworkTypeForSubscriber(subId, getOpPackageName());
-           } else {
-               // This can happen when the ITelephony interface is not up yet.
-               return NETWORK_TYPE_UNKNOWN;
-           }
-       } catch(RemoteException ex) {
-           // This shouldn't happen in the normal case
-           return NETWORK_TYPE_UNKNOWN;
-       } catch (NullPointerException ex) {
-           // This could happen before phone restarts due to crashing
-           return NETWORK_TYPE_UNKNOWN;
-       }
-   }
+    @UnsupportedAppUsage
+    public int getNetworkType(int subId) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.getNetworkTypeForSubscriber(subId, getOpPackageName());
+            } else {
+                // This can happen when the ITelephony interface is not up yet.
+                return NETWORK_TYPE_UNKNOWN;
+            }
+        } catch (RemoteException ex) {
+            // This shouldn't happen in the normal case
+            return NETWORK_TYPE_UNKNOWN;
+        } catch (NullPointerException ex) {
+            // This could happen before phone restarts due to crashing
+            return NETWORK_TYPE_UNKNOWN;
+        }
+    }
 
     /**
      * Returns a constant indicating the radio technology (network type)
@@ -2186,7 +2227,7 @@
      */
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
-    public int getDataNetworkType() {
+    public @NetworkType int getDataNetworkType() {
         return getDataNetworkType(getSubId(SubscriptionManager.getDefaultDataSubscriptionId()));
     }
 
@@ -2226,7 +2267,7 @@
      */
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
-    public int getVoiceNetworkType() {
+    public @NetworkType int getVoiceNetworkType() {
         return getVoiceNetworkType(getSubId());
     }
 
@@ -4105,11 +4146,16 @@
     }
 
     /**
-     * Returns the IMS home network domain name that was loaded from the ISIM.
-     * @return the IMS domain name, or null if not present or not loaded
+     * Returns the IMS home network domain name that was loaded from the ISIM {@see #APPTYPE_ISIM}.
+     * @return the IMS domain name. Returns {@code null} if ISIM hasn't been loaded or IMS domain
+     * hasn't been loaded or isn't present on the ISIM.
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public String getIsimDomain() {
         try {
             IPhoneSubInfo info = getSubscriberInfo();
@@ -4337,7 +4383,7 @@
     * @hide
     */
     private ITelecomService getTelecomService() {
-        return ITelecomService.Stub.asInterface(ServiceManager.getService(Context.TELECOM_SERVICE));
+        return ITelecomService.Stub.asInterface(ServiceManager.getService(TELECOM_SERVICE));
     }
 
     private ITelephonyRegistry getTelephonyRegistry() {
@@ -5367,7 +5413,19 @@
         }
     }
 
-    // ICC SIM Application Types
+    /**
+     * UICC SIM Application Types
+     * @hide
+     */
+    @IntDef(prefix = { "APPTYPE_" }, value = {
+            APPTYPE_SIM,
+            APPTYPE_USIM,
+            APPTYPE_RUIM,
+            APPTYPE_CSIM,
+            APPTYPE_ISIM
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface UiccAppType{}
     /** UICC application type is SIM */
     public static final int APPTYPE_SIM = PhoneConstants.APPTYPE_SIM;
     /** UICC application type is USIM */
@@ -5378,6 +5436,7 @@
     public static final int APPTYPE_CSIM = PhoneConstants.APPTYPE_CSIM;
     /** UICC application type is ISIM */
     public static final int APPTYPE_ISIM = PhoneConstants.APPTYPE_ISIM;
+
     // authContext (parameter P2) when doing UICC challenge,
     // per 3GPP TS 31.102 (Section 7.1.2)
     /** Authentication type for UICC challenge is EAP SIM. See RFC 4186 for details. */
@@ -5644,6 +5703,202 @@
         }
     }
 
+    /** @hide */
+    @IntDef(prefix = { "NETWORK_MODE_" }, value = {
+            NETWORK_MODE_WCDMA_PREF,
+            NETWORK_MODE_GSM_ONLY,
+            NETWORK_MODE_WCDMA_ONLY,
+            NETWORK_MODE_GSM_UMTS,
+            NETWORK_MODE_CDMA_EVDO,
+            NETWORK_MODE_CDMA_NO_EVDO,
+            NETWORK_MODE_EVDO_NO_CDMA,
+            NETWORK_MODE_GLOBAL,
+            NETWORK_MODE_LTE_CDMA_EVDO,
+            NETWORK_MODE_LTE_GSM_WCDMA,
+            NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA,
+            NETWORK_MODE_LTE_ONLY,
+            NETWORK_MODE_LTE_WCDMA,
+            NETWORK_MODE_TDSCDMA_ONLY,
+            NETWORK_MODE_TDSCDMA_WCDMA,
+            NETWORK_MODE_LTE_TDSCDMA,
+            NETWORK_MODE_TDSCDMA_GSM,
+            NETWORK_MODE_LTE_TDSCDMA_GSM,
+            NETWORK_MODE_TDSCDMA_GSM_WCDMA,
+            NETWORK_MODE_LTE_TDSCDMA_WCDMA,
+            NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA,
+            NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA,
+            NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PrefNetworkMode{}
+
+    /**
+     * preferred network mode is GSM/WCDMA (WCDMA preferred).
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_MODE_WCDMA_PREF = RILConstants.NETWORK_MODE_WCDMA_PREF;
+
+    /**
+     * preferred network mode is GSM only.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_MODE_GSM_ONLY = RILConstants.NETWORK_MODE_GSM_ONLY;
+
+    /**
+     * preferred network mode is WCDMA only.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_MODE_WCDMA_ONLY = RILConstants.NETWORK_MODE_WCDMA_ONLY;
+
+    /**
+     * preferred network mode is GSM/WCDMA (auto mode, according to PRL).
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_MODE_GSM_UMTS = RILConstants.NETWORK_MODE_GSM_UMTS;
+
+    /**
+     * preferred network mode is CDMA and EvDo (auto mode, according to PRL).
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_MODE_CDMA_EVDO = RILConstants.NETWORK_MODE_CDMA;
+
+    /**
+     * preferred network mode is CDMA only.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_MODE_CDMA_NO_EVDO = RILConstants.NETWORK_MODE_CDMA_NO_EVDO;
+
+    /**
+     * preferred network mode is EvDo only.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_MODE_EVDO_NO_CDMA = RILConstants.NETWORK_MODE_EVDO_NO_CDMA;
+
+    /**
+     * preferred network mode is GSM/WCDMA, CDMA, and EvDo (auto mode, according to PRL).
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_MODE_GLOBAL = RILConstants.NETWORK_MODE_GLOBAL;
+
+    /**
+     * preferred network mode is LTE, CDMA and EvDo.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_MODE_LTE_CDMA_EVDO = RILConstants.NETWORK_MODE_LTE_CDMA_EVDO;
+
+    /**
+     * preferred network mode is LTE, GSM/WCDMA.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_MODE_LTE_GSM_WCDMA = RILConstants.NETWORK_MODE_LTE_GSM_WCDMA;
+
+    /**
+     * preferred network mode is LTE, CDMA, EvDo, GSM/WCDMA.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA =
+            RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA;
+
+    /**
+     * preferred network mode is LTE Only.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_MODE_LTE_ONLY = RILConstants.NETWORK_MODE_LTE_ONLY;
+
+    /**
+     * preferred network mode is LTE/WCDMA.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_MODE_LTE_WCDMA = RILConstants.NETWORK_MODE_LTE_WCDMA;
+
+    /**
+     * preferred network mode is TD-SCDMA only.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_MODE_TDSCDMA_ONLY = RILConstants.NETWORK_MODE_TDSCDMA_ONLY;
+
+    /**
+     * preferred network mode is TD-SCDMA and WCDMA.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_MODE_TDSCDMA_WCDMA = RILConstants.NETWORK_MODE_TDSCDMA_WCDMA;
+
+    /**
+     * preferred network mode is TD-SCDMA and LTE.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_MODE_LTE_TDSCDMA = RILConstants.NETWORK_MODE_LTE_TDSCDMA;
+
+    /**
+     * preferred network mode is TD-SCDMA and GSM.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_MODE_TDSCDMA_GSM = RILConstants.NETWORK_MODE_TDSCDMA_GSM;
+
+    /**
+     * preferred network mode is TD-SCDMA,GSM and LTE.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_MODE_LTE_TDSCDMA_GSM =
+            RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM;
+
+    /**
+     * preferred network mode is TD-SCDMA, GSM/WCDMA.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_MODE_TDSCDMA_GSM_WCDMA =
+            RILConstants.NETWORK_MODE_TDSCDMA_GSM_WCDMA;
+
+    /**
+     * preferred network mode is TD-SCDMA, WCDMA and LTE.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_MODE_LTE_TDSCDMA_WCDMA =
+            RILConstants.NETWORK_MODE_LTE_TDSCDMA_WCDMA;
+
+    /**
+     * preferred network mode is TD-SCDMA, GSM/WCDMA and LTE.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA =
+            RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA;
+
+    /**
+     * preferred network mode is TD-SCDMA,EvDo,CDMA,GSM/WCDMA.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA =
+            RILConstants.NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA;
+    /**
+     * preferred network mode is TD-SCDMA/LTE/GSM/WCDMA, CDMA, and EvDo.
+     * @hide
+     */
+    @SystemApi
+    public static final int NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA =
+            RILConstants.NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA;
+
     /**
      * Get the preferred network type.
      * Used for device configuration by some CDMA operators.
@@ -5652,11 +5907,12 @@
      * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
      * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
-     * @return the preferred network type, defined in RILConstants.java.
+     * @return the preferred network type.
      * @hide
      */
-    @UnsupportedAppUsage
-    public int getPreferredNetworkType(int subId) {
+    @RequiresPermission((android.Manifest.permission.MODIFY_PHONE_STATE))
+    @SystemApi
+    public @PrefNetworkMode int getPreferredNetworkType(int subId) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
@@ -5787,21 +6043,46 @@
      * @param persistSelection whether the selection will persist until reboot. If true, only allows
      * attaching to the selected PLMN until reboot; otherwise, attach to the chosen PLMN and resume
      * normal network selection next time.
-     * @return true on success; false on any failure.
+     * @return {@code true} on success; {@code false} on any failure.
      */
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public boolean setNetworkSelectionModeManual(String operatorNumeric, boolean persistSelection) {
+        return setNetworkSelectionModeManual(
+                new OperatorInfo(
+                        "" /* operatorAlphaLong */, "" /* operatorAlphaShort */, operatorNumeric),
+                persistSelection);
+    }
+
+    /**
+     * Ask the radio to connect to the input network and change selection mode to manual.
+     *
+     * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
+     * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     *
+     * @param operatorInfo included the PLMN id, long name, short name of the operator to attach to.
+     * @param persistSelection whether the selection will persist until reboot. If true, only allows
+     * attaching to the selected PLMN until reboot; otherwise, attach to the chosen PLMN and resume
+     * normal network selection next time.
+     * @return {@code true} on success; {@code true} on any failure.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    public boolean setNetworkSelectionModeManual(
+            OperatorInfo operatorInfo, boolean persistSelection) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
                 return telephony.setNetworkSelectionModeManual(
-                        getSubId(), operatorNumeric, persistSelection);
+                        getSubId(), operatorInfo, persistSelection);
             }
         } catch (RemoteException ex) {
             Rlog.e(TAG, "setNetworkSelectionModeManual RemoteException", ex);
-        } catch (NullPointerException ex) {
-            Rlog.e(TAG, "setNetworkSelectionModeManual NPE", ex);
         }
         return false;
     }
@@ -6213,57 +6494,42 @@
     }
 
     /**
-     * @deprecated Use {@link android.telecom.TelecomManager#endCall()} instead.
+     * @removed Use {@link android.telecom.TelecomManager#endCall()} instead.
      * @hide
+     * @removed
      */
     @Deprecated
     @SystemApi
     @RequiresPermission(android.Manifest.permission.CALL_PHONE)
     public boolean endCall() {
-        try {
-            ITelephony telephony = getITelephony();
-            if (telephony != null)
-                return telephony.endCall();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#endCall", e);
-        }
         return false;
     }
 
     /**
-     * @deprecated Use {@link android.telecom.TelecomManager#acceptRingingCall} instead
+     * @removed Use {@link android.telecom.TelecomManager#acceptRingingCall} instead
      * @hide
+     * @removed
      */
     @Deprecated
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public void answerRingingCall() {
-        try {
-            ITelephony telephony = getITelephony();
-            if (telephony != null)
-                telephony.answerRingingCall();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#answerRingingCall", e);
-        }
+        // No-op
     }
 
     /**
-     * @deprecated Use {@link android.telecom.TelecomManager#silenceRinger} instead
+     * @removed Use {@link android.telecom.TelecomManager#silenceRinger} instead
      * @hide
      */
     @Deprecated
     @SystemApi
     @SuppressLint("Doclava125")
     public void silenceRinger() {
-        try {
-            getTelecomService().silenceRinger(getOpPackageName());
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelecomService#silenceRinger", e);
-        }
+        // No-op
     }
 
     /**
-     * @deprecated Use {@link android.telecom.TelecomManager#isInCall} instead
+     * @removed Use {@link android.telecom.TelecomManager#isInCall} instead
      * @hide
      */
     @Deprecated
@@ -6273,18 +6539,11 @@
             android.Manifest.permission.READ_PHONE_STATE
     })
     public boolean isOffhook() {
-        try {
-            ITelephony telephony = getITelephony();
-            if (telephony != null)
-                return telephony.isOffhook(getOpPackageName());
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#isOffhook", e);
-        }
         return false;
     }
 
     /**
-     * @deprecated Use {@link android.telecom.TelecomManager#isRinging} instead
+     * @removed Use {@link android.telecom.TelecomManager#isRinging} instead
      * @hide
      */
     @Deprecated
@@ -6294,18 +6553,11 @@
             android.Manifest.permission.READ_PHONE_STATE
     })
     public boolean isRinging() {
-        try {
-            ITelephony telephony = getITelephony();
-            if (telephony != null)
-                return telephony.isRinging(getOpPackageName());
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#isRinging", e);
-        }
         return false;
     }
 
     /**
-     * @deprecated Use {@link android.telecom.TelecomManager#isInCall} instead
+     * @removed Use {@link android.telecom.TelecomManager#isInCall} instead
      * @hide
      */
     @Deprecated
@@ -6315,13 +6567,6 @@
             android.Manifest.permission.READ_PHONE_STATE
     })
     public boolean isIdle() {
-        try {
-            ITelephony telephony = getITelephony();
-            if (telephony != null)
-                return telephony.isIdle(getOpPackageName());
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#isIdle", e);
-        }
         return true;
     }
 
@@ -7807,26 +8052,23 @@
     }
 
     /**
-     * Return the application ID for the app type like {@link APPTYPE_CSIM}.
+     * Return the application ID for the uicc application type like {@link #APPTYPE_CSIM}.
+     * All uicc applications are uniquely identified by application ID. See ETSI 102.221 and 101.220
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE}
      *
-     * Requires that the calling app has READ_PRIVILEGED_PHONE_STATE permission
-     *
-     * @param appType the uicc app type like {@link APPTYPE_CSIM}
-     * @return Application ID for specificied app type or null if no uicc or error.
+     * @param appType the uicc app type.
+     * @return Application ID for specified app type or {@code null} if no uicc or error.
      * @hide
      */
-    public String getAidForAppType(int appType) {
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public String getAidForAppType(@UiccAppType int appType) {
         return getAidForAppType(getSubId(), appType);
     }
 
     /**
-     * Return the application ID for the app type like {@link APPTYPE_CSIM}.
-     *
-     * Requires that the calling app has READ_PRIVILEGED_PHONE_STATE permission
-     *
-     * @param subId the subscription ID that this request applies to.
-     * @param appType the uicc app type, like {@link APPTYPE_CSIM}
-     * @return Application ID for specificied app type or null if no uicc or error.
+     * same as {@link #getAidForAppType(int)}
      * @hide
      */
     public String getAidForAppType(int subId, int appType) {
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index f0d3c89..5d6a8c1 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -118,7 +118,9 @@
      */
     public static final String EXTRA_CONFERENCE = "conference";
     /**
-     * @hide
+     * Boolean extra property set on an {@link ImsCallProfile} to indicate that this call is an
+     * emergency call.  The {@link ImsService} sets this on a call to indicate that the network has
+     * identified the call as an emergency call.
      */
     public static final String EXTRA_E_CALL = "e_call";
     /**
@@ -245,7 +247,8 @@
      * constants, the values passed for the {@link #EXTRA_CALL_RAT_TYPE} should be strings (e.g.
      * "14" vs (int) 14).
      * Note: This is used by {@link com.android.internal.telephony.imsphone.ImsPhoneConnection#
-     *      updateWifiStateFromExtras(Bundle)} to determine whether to set the
+     *      updateImsCallRatFromExtras(Bundle)} to determine whether to set the
+     * {@link android.telecom.TelecomManager#EXTRA_CALL_NETWORK_TYPE} extra value and
      * {@link android.telecom.Connection#PROPERTY_WIFI} property on a connection.
      */
     public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech";
diff --git a/telephony/java/android/telephony/mbms/GroupCall.java b/telephony/java/android/telephony/mbms/GroupCall.java
new file mode 100644
index 0000000..9aca18e
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/GroupCall.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.mbms;
+
+import android.annotation.IntDef;
+import android.os.RemoteException;
+import android.telephony.MbmsGroupCallSession;
+import android.telephony.mbms.vendor.IMbmsGroupCallService;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Class used to represent a single MBMS group call. After a call has been started with
+ * {@link MbmsGroupCallSession#startGroupCall},
+ * this class is used to hold information about the call and control it.
+ */
+public class GroupCall implements AutoCloseable {
+    private static final String LOG_TAG = "MbmsGroupCall";
+
+    /**
+     * The state of a group call, reported via
+     * {@link GroupCallCallback#onGroupCallStateChanged(int, int)}
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "STATE_" }, value = {STATE_STOPPED, STATE_STARTED, STATE_STALLED})
+    public @interface GroupCallState {}
+    public static final int STATE_STOPPED = 1;
+    public static final int STATE_STARTED = 2;
+    public static final int STATE_STALLED = 3;
+
+    /**
+     * The reason for a call state change, reported via
+     * {@link GroupCallCallback#onGroupCallStateChanged(int, int)}
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "REASON_" },
+            value = {REASON_BY_USER_REQUEST, REASON_FREQUENCY_CONFLICT,
+                    REASON_OUT_OF_MEMORY, REASON_NOT_CONNECTED_TO_HOMECARRIER_LTE,
+                    REASON_LEFT_MBMS_BROADCAST_AREA, REASON_NONE})
+    public @interface GroupCallStateChangeReason {}
+
+    /**
+     * Indicates that the middleware does not have a reason to provide for the state change.
+     */
+    public static final int REASON_NONE = 0;
+
+    /**
+     * State changed due to a call to {@link #close()} or
+     * {@link MbmsGroupCallSession#startGroupCall}
+     */
+    public static final int REASON_BY_USER_REQUEST = 1;
+
+    // 2 is unused to match up with streaming.
+
+    /**
+     * State changed due to a frequency conflict with another requested call.
+     */
+    public static final int REASON_FREQUENCY_CONFLICT = 3;
+
+    /**
+     * State changed due to the middleware running out of memory
+     */
+    public static final int REASON_OUT_OF_MEMORY = 4;
+
+    /**
+     * State changed due to the device leaving the home carrier's LTE network.
+     */
+    public static final int REASON_NOT_CONNECTED_TO_HOMECARRIER_LTE = 5;
+
+    /**
+     * State changed due to the device leaving the area where this call is being broadcast.
+     */
+    public static final int REASON_LEFT_MBMS_BROADCAST_AREA = 6;
+
+    private final int mSubscriptionId;
+    private final long mTmgi;
+    private final MbmsGroupCallSession mParentSession;
+    private final InternalGroupCallCallback mCallback;
+    private IMbmsGroupCallService mService;
+
+    /**
+     * @hide
+     */
+    public GroupCall(int subscriptionId,
+            IMbmsGroupCallService service,
+            MbmsGroupCallSession session,
+            long tmgi,
+            InternalGroupCallCallback callback) {
+        mSubscriptionId = subscriptionId;
+        mParentSession = session;
+        mService = service;
+        mTmgi = tmgi;
+        mCallback = callback;
+    }
+
+    /**
+     * Retrieve the TMGI (Temporary Mobile Group Identity) corresponding to this call.
+     */
+    public long getTmgi() {
+        return mTmgi;
+    }
+
+    /**
+     * Send an update to the middleware when the SAI (Service Area Identifier) list and frequency
+     * information of the group call has * changed. Callers must obtain this information from the
+     * wireless carrier independently.
+     * @param saiArray New array of SAIs that the call is available on.
+     * @param frequencyArray New array of frequencies that the call is available on.
+     */
+    public void updateGroupCall(int[] saiArray, int[] frequencyArray) {
+        if (mService == null) {
+            throw new IllegalStateException("No group call service attached");
+        }
+
+        try {
+            mService.updateGroupCall(mSubscriptionId, mTmgi, saiArray, frequencyArray);
+        } catch (RemoteException e) {
+            Log.w(LOG_TAG, "Remote process died");
+            mService = null;
+            sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
+        } finally {
+            mParentSession.onGroupCallStopped(this);
+        }
+    }
+
+    /**
+     * Stop this group call. Further operations on this object will fail with an
+     * {@link IllegalStateException}.
+     *
+     * May throw an {@link IllegalStateException}
+     */
+    @Override
+    public void close() {
+        if (mService == null) {
+            throw new IllegalStateException("No group call service attached");
+        }
+
+        try {
+            mService.stopGroupCall(mSubscriptionId, mTmgi);
+        } catch (RemoteException e) {
+            Log.w(LOG_TAG, "Remote process died");
+            mService = null;
+            sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
+        } finally {
+            mParentSession.onGroupCallStopped(this);
+        }
+    }
+
+    /** @hide */
+    public InternalGroupCallCallback getCallback() {
+        return mCallback;
+    }
+
+    private void sendErrorToApp(int errorCode, String message) {
+        mCallback.onError(errorCode, message);
+    }
+}
+
diff --git a/telephony/java/android/telephony/mbms/GroupCallCallback.java b/telephony/java/android/telephony/mbms/GroupCallCallback.java
new file mode 100644
index 0000000..001bb02
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/GroupCallCallback.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.mbms;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A callback class for use when the application is in a group call. The middleware
+ * will provide updates on the status of the call via this callback.
+ */
+public class GroupCallCallback {
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {
+            MbmsErrors.ERROR_NO_UNIQUE_MIDDLEWARE,
+            MbmsErrors.ERROR_MIDDLEWARE_LOST,
+            MbmsErrors.ERROR_MIDDLEWARE_NOT_BOUND,
+            MbmsErrors.GeneralErrors.ERROR_MIDDLEWARE_NOT_YET_READY,
+            MbmsErrors.GeneralErrors.ERROR_OUT_OF_MEMORY,
+            MbmsErrors.GeneralErrors.ERROR_MIDDLEWARE_TEMPORARILY_UNAVAILABLE,
+            MbmsErrors.GeneralErrors.ERROR_IN_E911,
+            MbmsErrors.GeneralErrors.ERROR_NOT_CONNECTED_TO_HOME_CARRIER_LTE,
+            MbmsErrors.GeneralErrors.ERROR_UNABLE_TO_READ_SIM,
+            MbmsErrors.GeneralErrors.ERROR_CARRIER_CHANGE_NOT_ALLOWED}, prefix = { "ERROR_" })
+    private @interface GroupCallError{}
+
+    /**
+     * Indicates broadcast signal strength is not available for this call.
+     *
+     * This may be due to the call no longer being available due to geography
+     * or timing (end of service)
+     */
+    public static final int SIGNAL_STRENGTH_UNAVAILABLE = -1;
+
+    /**
+     * Called by the middleware when it has detected an error condition in this group call. The
+     * possible error codes are listed in {@link MbmsErrors}.
+     * @param errorCode The error code.
+     * @param message A human-readable message generated by the middleware for debugging purposes.
+     */
+    public void onError(@GroupCallError int errorCode, @Nullable String message) {
+        // default implementation empty
+    }
+
+    /**
+     * Called to indicate this call has changed state.
+     *
+     * See {@link GroupCall#STATE_STOPPED}, {@link GroupCall#STATE_STARTED}
+     * and {@link GroupCall#STATE_STALLED}.
+     */
+    public void onGroupCallStateChanged(@GroupCall.GroupCallState int state,
+            @GroupCall.GroupCallStateChangeReason int reason) {
+        // default implementation empty
+    }
+
+    /**
+     * Broadcast Signal Strength updated.
+     *
+     * This signal strength is the BROADCAST signal strength which,
+     * depending on technology in play and it's deployment, may be
+     * stronger or weaker than the traditional UNICAST signal
+     * strength.  It a simple int from 0-4 for valid levels or
+     * {@link #SIGNAL_STRENGTH_UNAVAILABLE} if broadcast is not available
+     * for this call due to timing, geography or popularity.
+     */
+    public void onBroadcastSignalStrengthUpdated(int signalStrength) {
+        // default implementation empty
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/events/StartedDragingEvent.java b/telephony/java/android/telephony/mbms/IGroupCallCallback.aidl
old mode 100644
new mode 100755
similarity index 61%
rename from packages/SystemUI/src/com/android/systemui/stackdivider/events/StartedDragingEvent.java
rename to telephony/java/android/telephony/mbms/IGroupCallCallback.aidl
index 5d19851..844b634
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/events/StartedDragingEvent.java
+++ b/telephony/java/android/telephony/mbms/IGroupCallCallback.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2018 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -11,15 +11,16 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
  */
 
-package com.android.systemui.stackdivider.events;
-
-import com.android.systemui.recents.events.EventBus;
+package android.telephony.mbms;
 
 /**
- * Sent when the divider is being draged either manually or by an animation.
+ * @hide
  */
-public class StartedDragingEvent extends EventBus.Event {
+oneway interface IGroupCallCallback {
+    void onError(int errorCode, String message);
+    void onGroupCallStateChanged(int state, int reason);
+    void onBroadcastSignalStrengthUpdated(int signalStrength);
 }
diff --git a/telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl b/telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl
new file mode 100755
index 0000000..1a1c7f8
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl
@@ -0,0 +1,33 @@
+/*
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony.mbms;
+
+import java.util.List;
+
+/**
+ * @hide
+ */
+oneway interface IMbmsGroupCallSessionCallback
+{
+    void onError(int errorCode, String message);
+
+    void onAvailableSaisUpdated(in List currentSai, in List availableSais);
+
+    void onServiceInterfaceAvailable(String interfaceName, int index);
+
+    void onMiddlewareReady();
+}
diff --git a/telephony/java/android/telephony/mbms/InternalGroupCallCallback.java b/telephony/java/android/telephony/mbms/InternalGroupCallCallback.java
new file mode 100644
index 0000000..2910bb3
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/InternalGroupCallCallback.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.mbms;
+
+import android.os.Binder;
+
+import java.util.concurrent.Executor;
+
+/** @hide */
+public class InternalGroupCallCallback extends IGroupCallCallback.Stub {
+    private final GroupCallCallback mAppCallback;
+    private final Executor mExecutor;
+    private volatile boolean mIsStopped = false;
+
+    public InternalGroupCallCallback(GroupCallCallback appCallback,
+            Executor executor) {
+        mAppCallback = appCallback;
+        mExecutor = executor;
+    }
+
+    @Override
+    public void onError(final int errorCode, final String message) {
+        if (mIsStopped) {
+            return;
+        }
+
+        mExecutor.execute(new Runnable() {
+            @Override
+            public void run() {
+                long token = Binder.clearCallingIdentity();
+                try {
+                    mAppCallback.onError(errorCode, message);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void onGroupCallStateChanged(final int state, final int reason) {
+        if (mIsStopped) {
+            return;
+        }
+
+        mExecutor.execute(new Runnable() {
+            @Override
+            public void run() {
+                long token = Binder.clearCallingIdentity();
+                try {
+                    mAppCallback.onGroupCallStateChanged(state, reason);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void onBroadcastSignalStrengthUpdated(final int signalStrength) {
+        if (mIsStopped) {
+            return;
+        }
+
+        mExecutor.execute(new Runnable() {
+            @Override
+            public void run() {
+                long token = Binder.clearCallingIdentity();
+                try {
+                    mAppCallback.onBroadcastSignalStrengthUpdated(signalStrength);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        });
+    }
+
+    /** Prevents this callback from calling the app */
+    public void stop() {
+        mIsStopped = true;
+    }
+}
diff --git a/telephony/java/android/telephony/mbms/InternalGroupCallSessionCallback.java b/telephony/java/android/telephony/mbms/InternalGroupCallSessionCallback.java
new file mode 100644
index 0000000..4c9cf4d
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/InternalGroupCallSessionCallback.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.mbms;
+
+import android.os.Binder;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/** @hide */
+public class InternalGroupCallSessionCallback extends IMbmsGroupCallSessionCallback.Stub {
+    private final Executor mExecutor;
+    private final MbmsGroupCallSessionCallback mAppCallback;
+    private volatile boolean mIsStopped = false;
+
+    public InternalGroupCallSessionCallback(MbmsGroupCallSessionCallback appCallback,
+            Executor executor) {
+        mAppCallback = appCallback;
+        mExecutor = executor;
+    }
+
+    @Override
+    public void onError(final int errorCode, final String message) {
+        if (mIsStopped) {
+            return;
+        }
+
+        mExecutor.execute(new Runnable() {
+            @Override
+            public void run() {
+                long token = Binder.clearCallingIdentity();
+                try {
+                    mAppCallback.onError(errorCode, message);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void onAvailableSaisUpdated(final List currentSais, final List availableSais) {
+        if (mIsStopped) {
+            return;
+        }
+
+        mExecutor.execute(new Runnable() {
+            @Override
+            public void run() {
+                long token = Binder.clearCallingIdentity();
+                try {
+                    mAppCallback.onAvailableSaisUpdated(currentSais, availableSais);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void onServiceInterfaceAvailable(final String interfaceName, final int index) {
+        if (mIsStopped) {
+            return;
+        }
+
+        mExecutor.execute(new Runnable() {
+            @Override
+            public void run() {
+                long token = Binder.clearCallingIdentity();
+                try {
+                    mAppCallback.onServiceInterfaceAvailable(interfaceName, index);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void onMiddlewareReady() {
+        if (mIsStopped) {
+            return;
+        }
+
+        mExecutor.execute(new Runnable() {
+            @Override
+            public void run() {
+                long token = Binder.clearCallingIdentity();
+                try {
+                    mAppCallback.onMiddlewareReady();
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        });
+    }
+
+    /** Prevents this callback from calling the app */
+    public void stop() {
+        mIsStopped = true;
+    }
+}
diff --git a/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java b/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java
new file mode 100644
index 0000000..7da734e
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.mbms;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.telephony.MbmsGroupCallSession;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * A callback class that is used to receive information from the middleware on MBMS group-call
+ * services. An instance of this object should be passed into
+ * {@link MbmsGroupCallSession#create(Context, Executor, int, MbmsGroupCallSessionCallback)}.
+ */
+public class MbmsGroupCallSessionCallback {
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {
+            MbmsErrors.ERROR_NO_UNIQUE_MIDDLEWARE,
+            MbmsErrors.ERROR_MIDDLEWARE_LOST,
+            MbmsErrors.ERROR_MIDDLEWARE_NOT_BOUND,
+            MbmsErrors.InitializationErrors.ERROR_APP_PERMISSIONS_NOT_GRANTED,
+            MbmsErrors.InitializationErrors.ERROR_DUPLICATE_INITIALIZE,
+            MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
+            MbmsErrors.GeneralErrors.ERROR_MIDDLEWARE_NOT_YET_READY,
+            MbmsErrors.GeneralErrors.ERROR_OUT_OF_MEMORY,
+            MbmsErrors.GeneralErrors.ERROR_MIDDLEWARE_TEMPORARILY_UNAVAILABLE,
+            MbmsErrors.GeneralErrors.ERROR_IN_E911,
+            MbmsErrors.GeneralErrors.ERROR_NOT_CONNECTED_TO_HOME_CARRIER_LTE,
+            MbmsErrors.GeneralErrors.ERROR_UNABLE_TO_READ_SIM,
+            MbmsErrors.GeneralErrors.ERROR_CARRIER_CHANGE_NOT_ALLOWED}, prefix = { "ERROR_" })
+    private @interface GroupCallError{}
+
+    /**
+     * Called by the middleware when it has detected an error condition. The possible error codes
+     * are listed in {@link MbmsErrors}.
+     * @param errorCode The error code.
+     * @param message A human-readable message generated by the middleware for debugging purposes.
+     */
+    public void onError(@GroupCallError int errorCode, @Nullable String message) {
+    }
+
+    /**
+     * Indicates that the list of currently available SAIs has been updated. The app may use this
+     * information to filter the list of group calls when displaying available group calls to
+     * the user by matching the SAIs with a list of group calls separately negotiated with the
+     * carrier. The app may also report the aggregate list of SAIs to the group call application
+     * server so that a network entity can determine when, and where to activate the broadcast of
+     * particular group calls.
+     * @param currentSais The available SAIs on the current cell.
+     * @param availableSais A list of lists of available SAIS in neighboring cells, where each list
+     *                      contains the available SAIs in an individual cell.
+     */
+    public void onAvailableSaisUpdated(List<Integer> currentSais,
+            List<List<Integer>> availableSais) {
+    }
+
+    /**
+     * Called soon after the app calls {@link MbmsGroupCallSession#create}. The information supplied
+     * via this callback may be used to establish a data-link interface with the modem before the
+     * middleware is ready.
+     * Note that this method may be called before {@link #onMiddlewareReady()}.
+     *
+     * @param interfaceName The interface name for the data link.
+     * @param index The index for the data link.
+     */
+    public void onServiceInterfaceAvailable(String interfaceName, int index) {
+    }
+
+    /**
+     * Called to indicate that the middleware has been initialized and is ready.
+     *
+     * Before this method is called, calling any method on an instance of
+     * {@link MbmsGroupCallSession} will result in an {@link IllegalStateException} or an error
+     * delivered via {@link #onError(int, String)} with error code
+     * {@link MbmsErrors.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY}.
+     */
+    public void onMiddlewareReady() {
+    }
+}
diff --git a/telephony/java/android/telephony/mbms/MbmsUtils.java b/telephony/java/android/telephony/mbms/MbmsUtils.java
index 06b2120..95b4d37 100644
--- a/telephony/java/android/telephony/mbms/MbmsUtils.java
+++ b/telephony/java/android/telephony/mbms/MbmsUtils.java
@@ -23,6 +23,7 @@
 import android.content.pm.*;
 import android.content.pm.ServiceInfo;
 import android.telephony.MbmsDownloadSession;
+import android.telephony.MbmsGroupCallSession;
 import android.telephony.MbmsStreamingSession;
 import android.util.Log;
 
@@ -59,6 +60,9 @@
             case MbmsStreamingSession.MBMS_STREAMING_SERVICE_ACTION:
                 metaDataKey = MbmsStreamingSession.MBMS_STREAMING_SERVICE_OVERRIDE_METADATA;
                 break;
+            case MbmsGroupCallSession.MBMS_GROUP_CALL_SERVICE_ACTION:
+                metaDataKey = MbmsGroupCallSession.MBMS_GROUP_CALL_SERVICE_OVERRIDE_METADATA;
+                break;
         }
         if (metaDataKey == null) {
             return null;
diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl
new file mode 100755
index 0000000..721256a
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl
@@ -0,0 +1,39 @@
+/*
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony.mbms.vendor;
+
+import android.net.Uri;
+import android.telephony.mbms.IMbmsGroupCallSessionCallback;
+import android.telephony.mbms.IGroupCallCallback;
+
+/**
+ * @hide
+ */
+interface IMbmsGroupCallService
+{
+    int initialize(IMbmsGroupCallSessionCallback callback, int subId);
+
+    void stopGroupCall(int subId, long tmgi);
+
+    void updateGroupCall(int subscriptionId, long tmgi, in int[] saiArray,
+        in int[] frequencyArray);
+
+    int startGroupCall(int subscriptionId, long tmgi, in int[] saiArray,
+        in int[] frequencyArray, IGroupCallCallback callback);
+
+    void dispose(int subId);
+}
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsGroupCallServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsGroupCallServiceBase.java
new file mode 100644
index 0000000..3734ca7
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsGroupCallServiceBase.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.mbms.vendor;
+
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.telephony.mbms.GroupCallCallback;
+import android.telephony.mbms.IGroupCallCallback;
+import android.telephony.mbms.IMbmsGroupCallSessionCallback;
+import android.telephony.mbms.MbmsErrors;
+import android.telephony.mbms.MbmsGroupCallSessionCallback;
+import android.telephony.mbms.vendor.IMbmsGroupCallService.Stub;
+
+import java.util.List;
+
+/**
+ * Base class for MBMS group-call services. The middleware should override this class to implement
+ * its {@link Service} for group calls
+ * Subclasses should call this class's {@link #onBind} method to obtain an {@link IBinder} if they
+ * override {@link #onBind}.
+ * @hide
+ */
+@SystemApi
+@TestApi
+public class MbmsGroupCallServiceBase extends Service {
+    private final IBinder mInterface = new Stub() {
+        @Override
+        public int initialize(final IMbmsGroupCallSessionCallback callback,
+                final int subscriptionId) throws RemoteException {
+            if (callback == null) {
+                throw new NullPointerException("Callback must not be null");
+            }
+
+            final int uid = Binder.getCallingUid();
+
+            int result = MbmsGroupCallServiceBase.this.initialize(
+                    new MbmsGroupCallSessionCallback() {
+                        @Override
+                        public void onError(final int errorCode, final String message) {
+                            try {
+                                if (errorCode == MbmsErrors.UNKNOWN) {
+                                    throw new IllegalArgumentException(
+                                            "Middleware cannot send an unknown error.");
+                                }
+                                callback.onError(errorCode, message);
+                            } catch (RemoteException e) {
+                                onAppCallbackDied(uid, subscriptionId);
+                            }
+                        }
+
+                        @Override
+                        public void onAvailableSaisUpdated(final List currentSais,
+                                final List availableSais) {
+                            try {
+                                callback.onAvailableSaisUpdated(currentSais, availableSais);
+                            } catch (RemoteException e) {
+                                onAppCallbackDied(uid, subscriptionId);
+                            }
+                        }
+
+                        @Override
+                        public void onServiceInterfaceAvailable(final String interfaceName,
+                                final int index) {
+                            try {
+                                callback.onServiceInterfaceAvailable(interfaceName, index);
+                            } catch (RemoteException e) {
+                                onAppCallbackDied(uid, subscriptionId);
+                            }
+                        }
+
+                        @Override
+                        public void onMiddlewareReady() {
+                            try {
+                                callback.onMiddlewareReady();
+                            } catch (RemoteException e) {
+                                onAppCallbackDied(uid, subscriptionId);
+                            }
+                        }
+                    }, subscriptionId);
+
+            if (result == MbmsErrors.SUCCESS) {
+                callback.asBinder().linkToDeath(new DeathRecipient() {
+                    @Override
+                    public void binderDied() {
+                        onAppCallbackDied(uid, subscriptionId);
+                    }
+                }, 0);
+            }
+
+            return result;
+        }
+
+        @Override
+        public void stopGroupCall(int subId, long tmgi) {
+            MbmsGroupCallServiceBase.this.stopGroupCall(subId, tmgi);
+        }
+
+        @Override
+        public void updateGroupCall(int subscriptionId, long tmgi, int[] saiArray,
+                int[] frequencyArray) {
+            MbmsGroupCallServiceBase.this.updateGroupCall(
+                    subscriptionId, tmgi, saiArray, frequencyArray);
+        }
+
+        @Override
+        public int startGroupCall(final int subscriptionId, final long tmgi, final int[] saiArray,
+                final int[] frequencyArray, final IGroupCallCallback callback)
+                throws RemoteException {
+            if (callback == null) {
+                throw new NullPointerException("Callback must not be null");
+            }
+
+            final int uid = Binder.getCallingUid();
+
+            int result = MbmsGroupCallServiceBase.this.startGroupCall(
+                    subscriptionId, tmgi, saiArray, frequencyArray, new GroupCallCallback() {
+                        @Override
+                        public void onError(final int errorCode, final String message) {
+                            try {
+                                if (errorCode == MbmsErrors.UNKNOWN) {
+                                    throw new IllegalArgumentException(
+                                            "Middleware cannot send an unknown error.");
+                                }
+                                callback.onError(errorCode, message);
+                            } catch (RemoteException e) {
+                                onAppCallbackDied(uid, subscriptionId);
+                            }
+                        }
+
+                        public void onGroupCallStateChanged(int state, int reason) {
+                            try {
+                                callback.onGroupCallStateChanged(state, reason);
+                            } catch (RemoteException e) {
+                                onAppCallbackDied(uid, subscriptionId);
+                            }
+                        }
+
+                        public void onBroadcastSignalStrengthUpdated(int signalStrength) {
+                            try {
+                                callback.onBroadcastSignalStrengthUpdated(signalStrength);
+                            } catch (RemoteException e) {
+                                onAppCallbackDied(uid, subscriptionId);
+                            }
+                        }
+                    });
+
+            if (result == MbmsErrors.SUCCESS) {
+                callback.asBinder().linkToDeath(new DeathRecipient() {
+                    @Override
+                    public void binderDied() {
+                        onAppCallbackDied(uid, subscriptionId);
+                    }
+                }, 0);
+            }
+
+            return result;
+        }
+
+        @Override
+        public void dispose(int subId) throws RemoteException {
+            MbmsGroupCallServiceBase.this.dispose(subId);
+        }
+    };
+
+    /**
+     * Initialize the group call service for this app and subscription ID, registering the callback.
+     *
+     * May throw an {@link IllegalArgumentException} or a {@link SecurityException}, which
+     * will be intercepted and passed to the app as
+     * {@link MbmsErrors.InitializationErrors#ERROR_UNABLE_TO_INITIALIZE}
+     *
+     * May return any value from {@link MbmsErrors.InitializationErrors}
+     * or {@link MbmsErrors#SUCCESS}. Non-successful error codes will be passed to the app via
+     * {@link IMbmsGroupCallSessionCallback#onError(int, String)}.
+     *
+     * @param callback The callback to use to communicate with the app.
+     * @param subscriptionId The subscription ID to use.
+     */
+    public int initialize(MbmsGroupCallSessionCallback callback, int subscriptionId)
+            throws RemoteException {
+        throw new UnsupportedOperationException("Not implemented");
+    }
+
+    /**
+     * Starts a particular group call. This method may perform asynchronous work. When
+     * the call is ready for consumption, the middleware should inform the app via
+     * {@link IGroupCallCallback#onGroupCallStateChanged(int, int)}.
+     *
+     * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
+     *
+     * @param subscriptionId The subscription id to use.
+     * @param tmgi The TMGI, an identifier for the group call.
+     * @param saiArray An array of SAIs for the group call.
+     * @param frequencyArray An array of frequencies for the group call.
+     * @param callback The callback object on which the app wishes to receive updates.
+     * @return Any error in {@link MbmsErrors.GeneralErrors}
+     */
+    public int startGroupCall(int subscriptionId, long tmgi, int[] saiArray, int[] frequencyArray,
+            GroupCallCallback callback) {
+        throw new UnsupportedOperationException("Not implemented");
+    }
+
+    /**
+     * Stop the group call identified by {@code tmgi}.
+     *
+     * The callback provided via {@link #startGroupCall} should no longer be
+     * used after this method has called by the app.
+     *
+     * May throw an {@link IllegalStateException}
+     *
+     * @param subscriptionId The subscription id to use.
+     * @param tmgi The TMGI for the call to stop.
+     */
+    public void stopGroupCall(int subscriptionId, long tmgi) {
+        throw new UnsupportedOperationException("Not implemented");
+    }
+
+    /**
+     * Called when the app receives new SAI and frequency information for the group call identified
+     * by {@code tmgi}.
+     * @param saiArray New array of SAIs that the call is available on.
+     * @param frequencyArray New array of frequencies that the call is available on.
+     */
+    public void updateGroupCall(int subscriptionId, long tmgi, int[] saiArray,
+            int[] frequencyArray) {
+        throw new UnsupportedOperationException("Not implemented");
+    }
+
+    /**
+     * Signals that the app wishes to dispose of the session identified by the
+     * {@code subscriptionId} argument and the caller's uid. No notification back to the
+     * app is required for this operation, and the corresponding callback provided via
+     * {@link #initialize} should no longer be used
+     * after this method has been called by the app.
+     *
+     * May throw an {@link IllegalStateException}
+     *
+     * @param subscriptionId The subscription id to use.
+     */
+    public void dispose(int subscriptionId) throws RemoteException {
+        throw new UnsupportedOperationException("Not implemented");
+    }
+
+    /**
+     * Indicates that the app identified by the given UID and subscription ID has died.
+     * @param uid the UID of the app, as returned by {@link Binder#getCallingUid()}.
+     * @param subscriptionId The subscription ID the app is using.
+     */
+    public void onAppCallbackDied(int uid, int subscriptionId) {
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mInterface;
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 6521f0b..0ccd748 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -232,5 +232,5 @@
      */
     int getSimStateForSlotIndex(int slotIndex);
 
-    boolean isActiveSubId(int subId);
+    boolean isActiveSubId(int subId, String callingPackage);
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index c0bccde..ca2bcff 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -75,116 +75,6 @@
     void call(String callingPackage, String number);
 
     /**
-     * End call if there is a call in progress, otherwise does nothing.
-     *
-     * @return whether it hung up
-     */
-    boolean endCall();
-
-    /**
-     * End call on particular subId or go to the Home screen
-     * @param subId user preferred subId.
-     * @return whether it hung up
-     */
-    boolean endCallForSubscriber(int subId);
-
-    /**
-     * Answer the currently-ringing call.
-     *
-     * If there's already a current active call, that call will be
-     * automatically put on hold.  If both lines are currently in use, the
-     * current active call will be ended.
-     *
-     * TODO: provide a flag to let the caller specify what policy to use
-     * if both lines are in use.  (The current behavior is hardwired to
-     * "answer incoming, end ongoing", which is how the CALL button
-     * is specced to behave.)
-     *
-     * TODO: this should be a oneway call (especially since it's called
-     * directly from the key queue thread).
-     */
-    void answerRingingCall();
-
-    /**
-     * Answer the currently-ringing call on particular subId .
-     *
-     * If there's already a current active call, that call will be
-     * automatically put on hold.  If both lines are currently in use, the
-     * current active call will be ended.
-     *
-     * TODO: provide a flag to let the caller specify what policy to use
-     * if both lines are in use.  (The current behavior is hardwired to
-     * "answer incoming, end ongoing", which is how the CALL button
-     * is specced to behave.)
-     *
-     * TODO: this should be a oneway call (especially since it's called
-     * directly from the key queue thread).
-     */
-    void answerRingingCallForSubscriber(int subId);
-
-    /**
-     * Silence the ringer if an incoming call is currently ringing.
-     * (If vibrating, stop the vibrator also.)
-     *
-     * It's safe to call this if the ringer has already been silenced, or
-     * even if there's no incoming call.  (If so, this method will do nothing.)
-     *
-     * TODO: this should be a oneway call too (see above).
-     *       (Actually *all* the methods here that return void can
-     *       probably be oneway.)
-     */
-    void silenceRinger();
-
-    /**
-     * Check if we are in either an active or holding call
-     * @param callingPackage the name of the package making the call.
-     * @return true if the phone state is OFFHOOK.
-     */
-    boolean isOffhook(String callingPackage);
-
-    /**
-     * Check if a particular subId has an active or holding call
-     *
-     * @param subId user preferred subId.
-     * @param callingPackage the name of the package making the call.
-     * @return true if the phone state is OFFHOOK.
-     */
-    boolean isOffhookForSubscriber(int subId, String callingPackage);
-
-    /**
-     * Check if an incoming phone call is ringing or call waiting
-     * on a particular subId.
-     *
-     * @param subId user preferred subId.
-     * @param callingPackage the name of the package making the call.
-     * @return true if the phone state is RINGING.
-     */
-    boolean isRingingForSubscriber(int subId, String callingPackage);
-
-    /**
-     * Check if an incoming phone call is ringing or call waiting.
-     * @param callingPackage the name of the package making the call.
-     * @return true if the phone state is RINGING.
-     */
-    boolean isRinging(String callingPackage);
-
-    /**
-     * Check if the phone is idle.
-     * @param callingPackage the name of the package making the call.
-     * @return true if the phone state is IDLE.
-     */
-    boolean isIdle(String callingPackage);
-
-    /**
-     * Check if the phone is idle on a particular subId.
-     *
-     * @param subId user preferred subId.
-     * @param callingPackage the name of the package making the call.
-     * @return true if the phone state is IDLE.
-     */
-    boolean isIdleForSubscriber(int subId, String callingPackage);
-
-    /**
      * Check to see if the radio is on or not.
      * @param callingPackage the name of the package making the call.
      * @return returns true if the radio is on.
@@ -865,14 +755,15 @@
      * Ask the radio to connect to the input network and change selection mode to manual.
      *
      * @param subId the id of the subscription.
-     * @param operatorNumeric the PLMN of the operator to attach to.
-     * @param persistSelection Whether the selection will persist until reboot. If true, only allows
+     * @param operatorInfo the operator inforamtion, included the PLMN, long name and short name of
+     * the operator to attach to.
+     * @param persistSelection whether the selection will persist until reboot. If true, only allows
      * attaching to the selected PLMN until reboot; otherwise, attach to the chosen PLMN and resume
      * normal network selection next time.
-     * @return true if the request suceeded.
+     * @return {@code true} on success; {@code true} on any failure.
      */
-    boolean setNetworkSelectionModeManual(int subId, in String operatorNumeric,
-            boolean persistSelection);
+    boolean setNetworkSelectionModeManual(
+            int subId, in OperatorInfo operatorInfo, boolean persisSelection);
 
     /**
      * Set the preferred network type.
@@ -1586,4 +1477,19 @@
      * Return the network selection mode on the subscription with id {@code subId}.
      */
      int getNetworkSelectionMode(int subId);
+
+    /**
+     * Get a list of SMS apps on a user.
+     */
+    String[] getSmsApps(int userId);
+
+    /**
+     * Get the default SMS app on a given user.
+     */
+    String getDefaultSmsApp(int userId);
+
+    /**
+     * Set the default SMS app to a given package on a given user.
+     */
+    void setDefaultSmsApp(int userId, String packageName);
 }
diff --git a/telephony/java/com/android/internal/telephony/OperatorInfo.java b/telephony/java/com/android/internal/telephony/OperatorInfo.java
index d0245a0..a47e2b0 100644
--- a/telephony/java/com/android/internal/telephony/OperatorInfo.java
+++ b/telephony/java/com/android/internal/telephony/OperatorInfo.java
@@ -21,7 +21,7 @@
 import android.os.Parcelable;
 
 /**
- * {@hide}
+ * @hide
  */
 public class OperatorInfo implements Parcelable {
     public enum State {
diff --git a/telephony/java/com/android/internal/telephony/SmsApplication.java b/telephony/java/com/android/internal/telephony/SmsApplication.java
index d8ef429..39722c6 100644
--- a/telephony/java/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/java/com/android/internal/telephony/SmsApplication.java
@@ -209,7 +209,14 @@
      * Support smsto Uri scheme.
      */
     public static Collection<SmsApplicationData> getApplicationCollection(Context context) {
-        int userId = getIncomingUserId(context);
+        return getApplicationCollectionAsUser(context, getIncomingUserId(context));
+    }
+
+    /**
+     * Same as {@link #getApplicationCollection} but it takes a target user ID.
+     */
+    public static Collection<SmsApplicationData> getApplicationCollectionAsUser(Context context,
+            int userId) {
         final long token = Binder.clearCallingIdentity();
         try {
             return getApplicationCollectionInternal(context, userId);
@@ -535,13 +542,20 @@
      * needs to have permission to set AppOps and write to secure settings.
      */
     public static void setDefaultApplication(String packageName, Context context) {
+        setDefaultApplicationAsUser(packageName, context, getIncomingUserId(context));
+    }
+
+    /**
+     * Same as {@link #setDefaultApplication} but takes a target user id.
+     */
+    public static void setDefaultApplicationAsUser(String packageName, Context context,
+            int userId) {
         TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
         if (!tm.isSmsCapable()) {
             // No phone, no SMS
             return;
         }
 
-        final int userId = getIncomingUserId(context);
         final long token = Binder.clearCallingIdentity();
         try {
             setDefaultApplicationInternal(packageName, context, userId);
@@ -552,6 +566,8 @@
 
     private static void setDefaultApplicationInternal(String packageName, Context context,
             int userId) {
+        final UserHandle userHandle = UserHandle.of(userId);
+
         // Get old package name
         String oldPackageName = Settings.Secure.getStringForUser(context.getContentResolver(),
                 Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
@@ -628,7 +644,7 @@
                 if (DEBUG_MULTIUSER) {
                     Log.i(LOG_TAG, "setDefaultApplicationInternal old=" + oldAppData.mPackageName);
                 }
-                context.sendBroadcast(oldAppIntent);
+                context.sendBroadcastAsUser(oldAppIntent, userHandle);
             }
             // Notify the new sms app that it's now the default (if the new sms app has a receiver
             // to handle the changed default sms intent).
@@ -646,8 +662,16 @@
                 if (DEBUG_MULTIUSER) {
                     Log.i(LOG_TAG, "setDefaultApplicationInternal new=" + packageName);
                 }
-                context.sendBroadcast(intent);
+                context.sendBroadcastAsUser(intent, userHandle);
             }
+
+            // Send an implicit broadcast for the system server.
+            // (or anyone with MONITOR_DEFAULT_SMS_PACKAGE, really.)
+            final Intent intent =
+                    new Intent(Telephony.Sms.Intents.ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL);
+            context.sendBroadcastAsUser(intent, userHandle,
+                    permission.MONITOR_DEFAULT_SMS_PACKAGE);
+
             MetricsLogger.action(context, MetricsEvent.ACTION_DEFAULT_SMS_APP_CHANGED,
                     applicationData.mPackageName);
         }
@@ -799,7 +823,18 @@
      * @return component name of the app and class to deliver SMS messages to
      */
     public static ComponentName getDefaultSmsApplication(Context context, boolean updateIfNeeded) {
-        int userId = getIncomingUserId(context);
+        return getDefaultSmsApplicationAsUser(context, updateIfNeeded, getIncomingUserId(context));
+    }
+
+    /**
+     * Gets the default SMS application on a given user
+     * @param context context from the calling app
+     * @param updateIfNeeded update the default app if there is no valid default app configured.
+     * @param userId target user ID.
+     * @return component name of the app and class to deliver SMS messages to
+     */
+    public static ComponentName getDefaultSmsApplicationAsUser(Context context,
+            boolean updateIfNeeded, int userId) {
         final long token = Binder.clearCallingIdentity();
         try {
             ComponentName component = null;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index 06378ba..23ea237 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -21,6 +21,7 @@
 import android.app.AppOpsManager;
 import android.content.Context;
 import android.os.Binder;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.telephony.Rlog;
@@ -307,4 +308,17 @@
         Rlog.e(LOG_TAG, "Phone process is down, cannot check carrier privileges");
         return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
     }
+
+    /**
+     * Throws if the caller is not of a shell (or root) UID.
+     *
+     * @param callingUid pass Binder.callingUid().
+     */
+    public static void enforceShellOnly(int callingUid, String message) {
+        if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
+            return; // okay
+        }
+
+        throw new SecurityException(message + ": Only shell user can call it");
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java b/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
index 6bf22a0..8015b07 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
@@ -33,6 +33,7 @@
 import com.android.internal.telephony.SmsConstants;
 
 import java.io.UnsupportedEncodingException;
+import java.util.Locale;
 
 /**
  * Parses a GSM or UMTS format SMS-CB message into an {@link SmsCbMessage} object. The class is
@@ -44,16 +45,34 @@
      * Languages in the 0000xxxx DCS group as defined in 3GPP TS 23.038, section 5.
      */
     private static final String[] LANGUAGE_CODES_GROUP_0 = {
-            "de", "en", "it", "fr", "es", "nl", "sv", "da", "pt", "fi", "no", "el", "tr", "hu",
-            "pl", null
+            Locale.GERMAN.getLanguage(),        // German
+            Locale.ENGLISH.getLanguage(),       // English
+            Locale.ITALIAN.getLanguage(),       // Italian
+            Locale.FRENCH.getLanguage(),        // French
+            new Locale("es").getLanguage(),     // Spanish
+            new Locale("nl").getLanguage(),     // Dutch
+            new Locale("sv").getLanguage(),     // Swedish
+            new Locale("da").getLanguage(),     // Danish
+            new Locale("pt").getLanguage(),     // Portuguese
+            new Locale("fi").getLanguage(),     // Finnish
+            new Locale("nb").getLanguage(),     // Norwegian
+            new Locale("el").getLanguage(),     // Greek
+            new Locale("tr").getLanguage(),     // Turkish
+            new Locale("hu").getLanguage(),     // Hungarian
+            new Locale("pl").getLanguage(),     // Polish
+            null
     };
 
     /**
      * Languages in the 0010xxxx DCS group as defined in 3GPP TS 23.038, section 5.
      */
     private static final String[] LANGUAGE_CODES_GROUP_2 = {
-            "cs", "he", "ar", "ru", "is", null, null, null, null, null, null, null, null, null,
-            null, null
+            new Locale("cs").getLanguage(),     // Czech
+            new Locale("he").getLanguage(),     // Hebrew
+            new Locale("ar").getLanguage(),     // Arabic
+            new Locale("ru").getLanguage(),     // Russian
+            new Locale("is").getLanguage(),     // Icelandic
+            null, null, null, null, null, null, null, null, null, null, null
     };
 
     private static final char CARRIAGE_RETURN = 0x0d;
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsCbConstants.java b/telephony/java/com/android/internal/telephony/gsm/SmsCbConstants.java
index 0fabc2f..541ca8d 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsCbConstants.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsCbConstants.java
@@ -118,71 +118,103 @@
     public static final int MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE
             = 0x111E; // 4382
 
-    /** CMAS Message Identifier for Presidential Level alerts for additional languages
-     *  for additional languages. */
+    /**
+     * CMAS Message Identifier for Presidential Level alerts for additional languages.
+     */
     public static final int MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL_LANGUAGE
             = 0x111F; // 4383
 
-    /** CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Observed
-     *  for additional languages. */
+    /**
+     * CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Observed
+     * for additional languages.
+     */
     public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED_LANGUAGE
             = 0x1120; // 4384
 
-    /** CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Likely
-     *  for additional languages. */
+    /**
+     * CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Likely
+     *  for additional languages.
+     */
     public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY_LANGUAGE
             = 0x1121; // 4385
 
-    /** CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Observed
-     *  for additional languages. */
+    /**
+     * CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Observed
+     * for additional languages.
+     */
     public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED_LANGUAGE
             = 0x1122; // 4386
 
-    /** CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Likely
-     *  for additional languages. */
+    /**
+     * CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Likely
+     * for additional languages.
+     */
     public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY_LANGUAGE
             = 0x1123; // 4387
 
-    /** CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Observed
-     *  for additional languages. */
+    /**
+     * CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Observed
+     * for additional languages.
+     */
     public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED_LANGUAGE
             = 0x1124; // 4388
 
-    /** CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Likely
-     *  for additional languages.*/
+    /**
+     * CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Likely
+     * for additional languages.
+     */
     public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY_LANGUAGE
             = 0x1125; // 4389
 
-    /** CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Observed
-     *  for additional languages. */
+    /**
+     * CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Observed
+     * for additional languages.
+     */
     public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED_LANGUAGE
             = 0x1126; // 4390
 
-    /** CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Likely
-     *  for additional languages.*/
+    /**
+     * CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Likely
+     * for additional languages.
+     */
     public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY_LANGUAGE
             = 0x1127; // 4391
 
-    /** CMAS Message Identifier for Child Abduction Emergency (Amber Alert)
-     *  for additional languages. */
+    /**
+     * CMAS Message Identifier for Child Abduction Emergency (Amber Alert)
+     * for additional languages.
+     */
     public static final int MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY_LANGUAGE
             = 0x1128; // 4392
 
-    /** CMAS Message Identifier for the Required Monthly Test
-     *  for additional languages. */
+    /** CMAS Message Identifier for the Required Monthly Test  for additional languages. */
     public static final int MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST_LANGUAGE
             = 0x1129; // 4393
 
-    /** CMAS Message Identifier for CMAS Exercise
-     *  for additional languages. */
+    /** CMAS Message Identifier for CMAS Exercise for additional languages. */
     public static final int MESSAGE_ID_CMAS_ALERT_EXERCISE_LANGUAGE
             = 0x112A; // 4394
 
-    /** CMAS Message Identifier for operator defined use
-     *  for additional languages. */
+    /** CMAS Message Identifier for operator defined use for additional languages. */
     public static final int MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE_LANGUAGE
             = 0x112B; // 4395
 
+    /** CMAS Message Identifier for CMAS Public Safety Alerts. */
+    public static final int MESSAGE_ID_CMAS_ALERT_PUBLIC_SAFETY
+            = 0x112C; // 4396
+
+    /** CMAS Message Identifier for CMAS Public Safety Alerts for additional languages. */
+    public static final int MESSAGE_ID_CMAS_ALERT_PUBLIC_SAFETY_LANGUAGE
+            = 0x112D; // 4397
+
+    /** CMAS Message Identifier for CMAS State/Local Test. */
+    public static final int MESSAGE_ID_CMAS_ALERT_STATE_LOCAL_TEST
+            = 0x112E; // 4398
+
+    /** CMAS Message Identifier for CMAS State/Local Test for additional languages. */
+    public static final int MESSAGE_ID_CMAS_ALERT_STATE_LOCAL_TEST_LANGUAGE
+            = 0x112F; // 4399
+
     /** End of CMAS Message Identifier range (including future extensions). */
     public static final int MESSAGE_ID_CMAS_LAST_IDENTIFIER
             = 0x112F; // 4399
diff --git a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
index 4790b75..6b3df94 100644
--- a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
+++ b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
@@ -93,11 +93,23 @@
      *     converted. If the array size is more than needed, the rest of array remains unchanged.
      */
     public static void bcdToBytes(String bcd, byte[] bytes) {
+        bcdToBytes(bcd, bytes, 0);
+    }
+
+    /**
+     * Converts BCD string to bytes and put it into the given byte array.
+     *
+     * @param bcd This should have an even length. If not, an "0" will be appended to the string.
+     * @param bytes If the array size is less than needed, the rest of the BCD string isn't be
+     *     converted. If the array size is more than needed, the rest of array remains unchanged.
+     * @param offset the offset into the bytes[] to fill the data
+     */
+    public static void bcdToBytes(String bcd, byte[] bytes, int offset) {
         if (bcd.length() % 2 != 0) {
             bcd += "0";
         }
-        int size = Math.min(bytes.length * 2, bcd.length());
-        for (int i = 0, j = 0; i + 1 < size; i += 2, j++) {
+        int size = Math.min((bytes.length - offset) * 2, bcd.length());
+        for (int i = 0, j = offset; i + 1 < size; i += 2, j++) {
             bytes[j] = (byte) (charToByte(bcd.charAt(i + 1)) << 4 | charToByte(bcd.charAt(i)));
         }
     }
@@ -125,6 +137,20 @@
     }
 
     /**
+     * Convert a 5 or 6 - digit PLMN string to a nibble-swizzled encoding as per 24.008 10.5.1.3
+     *
+     * @param plmn the PLMN to convert
+     * @param data a byte array for the output
+     * @param offset the offset into data to start writing
+     */
+    public static void stringToBcdPlmn(final String plmn, byte[] data, int offset) {
+        char digit6 = (plmn.length() > 5) ? plmn.charAt(5) : 'F';
+        data[offset] = (byte) (charToByte(plmn.charAt(1)) << 4 | charToByte(plmn.charAt(0)));
+        data[offset + 1] = (byte) (charToByte(digit6) << 4 | charToByte(plmn.charAt(2)));
+        data[offset + 2] = (byte) (charToByte(plmn.charAt(4)) << 4 | charToByte(plmn.charAt(3)));
+    }
+
+    /**
      * Some fields (like ICC ID) in GSM SIMs are stored as nibble-swizzled BCH
      */
     public static String
@@ -844,7 +870,7 @@
     }
 
     /**
-     * Converts a character of [0-9a-aA-F] to its hex value in a byte. If the character is not a
+     * Converts a character of [0-9a-fA-F] to its hex value in a byte. If the character is not a
      * hex number, 0 will be returned.
      */
     private static byte charToByte(char c) {
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 4a6fe49..1f60b71 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -247,8 +247,14 @@
                     mIterationCycle = false;
                     // In the "applaunch.txt" file, trail launches is referenced using
                     // "TRIAL_LAUNCH"
-                    String appPkgName = mNameToIntent.get(launch.getApp())
-                        .getComponent().getPackageName();
+                    Intent startIntent = mNameToIntent.get(launch.getApp());
+                    if (startIntent == null) {
+                        Log.w(TAG, "App does not exist: " + launch.getApp());
+                        mResult.putString(mNameToResultKey.get(launch.getApp()),
+                            "App does not exist");
+                        continue;
+                    }
+                    String appPkgName = startIntent.getComponent().getPackageName();
                     if (SPEED_PROFILE_FILTER.equals(launch.getCompilerFilter())) {
                         assertTrue(String.format("Not able to compile the app : %s", appPkgName),
                               compileApp(VERIFY_FILTER, appPkgName));
diff --git a/tests/DexLoggerIntegrationTests/AndroidManifest.xml b/tests/DexLoggerIntegrationTests/AndroidManifest.xml
index a847e8f..a9f01ed 100644
--- a/tests/DexLoggerIntegrationTests/AndroidManifest.xml
+++ b/tests/DexLoggerIntegrationTests/AndroidManifest.xml
@@ -17,10 +17,10 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.frameworks.dexloggertest">
 
-    <!-- Tests feature introduced in P (27) -->
+    <!-- Tests feature introduced in P (28) -->
     <uses-sdk
-        android:minSdkVersion="27"
-        android:targetSdkVersion="27" />
+        android:minSdkVersion="28"
+        android:targetSdkVersion="28" />
 
     <uses-permission android:name="android.permission.READ_LOGS" />
 
diff --git a/tests/ImfTest/Android.mk b/tests/ImfTest/Android.mk
deleted file mode 100644
index a8f5b08..0000000
--- a/tests/ImfTest/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-# Only compile source java files in this apk.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := ImfTest
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-include $(BUILD_PACKAGE)
-
-# Use the following include to make our test apk.
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/ImfTest/AndroidManifest.xml b/tests/ImfTest/AndroidManifest.xml
deleted file mode 100644
index 82dbe75..0000000
--- a/tests/ImfTest/AndroidManifest.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
-        package="com.android.imftest">
-
-   <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
-
-   <application>
-    
-        <activity android:name=".samples.InputTypeActivity" android:label="Input Type Activity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.LAUNCHER" />
-                <category android:name="android.intent.category.IMF_TEST" />
-            </intent-filter>
-        </activity>
-                
-        <activity android:name=".samples.ButtonActivity" android:label="Button Activity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.LAUNCHER" />
-                <category android:name="android.intent.category.IMF_TEST" />
-            </intent-filter>
-        </activity>
-        
-        <activity android:name=".samples.BigEditTextActivityNonScrollablePanScan" android:label="Big ET !Scroll Pan/Scan">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.LAUNCHER" />
-                <category android:name="android.intent.category.IMF_TEST" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name=".samples.ManyEditTextActivityNoScrollPanScan" android:label="ManyEditTextActivityNoScrollPanScan">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.LAUNCHER" />
-                <category android:name="android.intent.category.IMF_TEST" />
-            </intent-filter>
-        </activity>
-        
-        <activity android:name=".samples.BigEditTextActivityNonScrollableResize" android:label="Big ET !Scroll Resize">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.LAUNCHER" />
-                <category android:name="android.intent.category.IMF_TEST" />
-            </intent-filter>
-        </activity>
-        
-        <activity android:name=".samples.BigEditTextActivityScrollablePanScan" android:label="Big ET Scroll Pan/Scan">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.LAUNCHER" />
-                <category android:name="android.intent.category.IMF_TEST" />
-            </intent-filter>
-        </activity>
-        
-        <activity android:name=".samples.BigEditTextActivityScrollableResize" android:label="Big ET Scroll Resize">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.LAUNCHER" />
-                <category android:name="android.intent.category.IMF_TEST" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name=".samples.EditTextActivityDialog" android:label="ET Dialog">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.LAUNCHER" />
-                <category android:name="android.intent.category.IMF_TEST" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name=".samples.ManyEditTextActivityScrollPanScan" android:label="ManyEditTextActivityScrollPanScan">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.LAUNCHER" />
-                <category android:name="android.intent.category.IMF_TEST" />
-            </intent-filter>
-        </activity>
-        
-        <activity android:name=".samples.ManyEditTextActivityScrollResize" android:label="ManyEditTextActivityScrollResize">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.LAUNCHER" />
-                <category android:name="android.intent.category.IMF_TEST" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name=".samples.BottomEditTextActivityPanScan" android:label="BottomEditTextActivityPanScan">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.LAUNCHER" />
-                <category android:name="android.intent.category.IMF_TEST" />
-            </intent-filter>
-        </activity>
-        
-        <activity android:name=".samples.BottomEditTextActivityResize" android:label="BottomEditTextActivityResize">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.LAUNCHER" />
-                <category android:name="android.intent.category.IMF_TEST" />
-            </intent-filter>
-        </activity>
-        
-        <activity android:name=".samples.OneEditTextActivitySelected" android:label="OneEditTextActivitySelected">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.LAUNCHER" />
-                <category android:name="android.intent.category.IMF_TEST" />
-            </intent-filter>
-        </activity>
-    
-        <activity android:name=".samples.OneEditTextActivityNotSelected" android:label="OneEditTextActivityNotSelected">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.LAUNCHER" />
-                <category android:name="android.intent.category.IMF_TEST" />
-            </intent-filter>
-        </activity>
-         
-        <activity android:name=".samples.AutoCompleteTextViewActivityPortrait" android:label="AutoCompleteTextViewActivityPortrait" android:screenOrientation="portrait">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.LAUNCHER" />
-                <category android:name="android.intent.category.IMF_TEST" />
-            </intent-filter>
-        </activity>
-   
-        <activity android:name=".samples.AutoCompleteTextViewActivityLandscape" android:label="AutoCompleteTextViewActivityLandscape" android:screenOrientation="landscape">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.LAUNCHER" />
-                <category android:name="android.intent.category.IMF_TEST" />
-            </intent-filter>
-        </activity>   
-        
-        <activity android:name=".samples.DialogActivity" android:label="DialogActivity" android:screenOrientation="portrait">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.LAUNCHER" />
-                <category android:name="android.intent.category.IMF_TEST" />
-            </intent-filter>
-        </activity>              
-          
-    </application>
-    
-</manifest>
diff --git a/tests/ImfTest/res/layout/dialog_edit_text_no_scroll.xml b/tests/ImfTest/res/layout/dialog_edit_text_no_scroll.xml
deleted file mode 100644
index 1a2b7eb..0000000
--- a/tests/ImfTest/res/layout/dialog_edit_text_no_scroll.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:padding="20dip"
-    android:orientation="vertical">
-            
-    <View
-    	android:id="@+id/blank"
-    	android:layout_height="0dip"
-    	android:layout_width="match_parent"
-    	android:layout_weight="1"/>
-    	
-    <EditText
-        android:id="@+id/dialog_edit_text"
-        android:layout_height="wrap_content"
-        android:layout_width="match_parent"
-        android:scrollHorizontally="true"
-        android:textAppearance="?android:attr/textAppearanceMedium" />
-
-</LinearLayout>
diff --git a/tests/ImfTest/res/layout/full_screen_edit_text.xml b/tests/ImfTest/res/layout/full_screen_edit_text.xml
deleted file mode 100644
index e760ac1..0000000
--- a/tests/ImfTest/res/layout/full_screen_edit_text.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/samples/SampleCode/res/layout/baseline_1.xml
-**
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<EditText xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/data" 
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:minLines="15"
-    android:gravity="top"/>
-
diff --git a/tests/ImfTest/res/layout/one_edit_text_activity.xml b/tests/ImfTest/res/layout/one_edit_text_activity.xml
deleted file mode 100644
index 0558228..0000000
--- a/tests/ImfTest/res/layout/one_edit_text_activity.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/samples/SampleCode/res/layout/baseline_1.xml
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:orientation="vertical"
->
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical"
-        android:baselineAligned="false">
-
-        <View android:id="@+id/blank"
-            android:layout_height="0dip"
-            android:layout_width="match_parent"
-            android:layout_weight="1"
-        />
-
-        <EditText android:id="@+id/dialog_edit_text"
-            android:layout_height="wrap_content"
-            android:layout_width="match_parent"
-            android:scrollHorizontally="true"
-            android:textAppearance="?android:attr/textAppearanceMedium"
-        />
-    </LinearLayout>
-
-    <View
-        android:layout_width="match_parent"
-        android:layout_height="1dip"
-        android:background="@android:drawable/divider_horizontal_dark"
-    />
-</LinearLayout>
diff --git a/tests/ImfTest/res/layout/sample_edit_text.xml b/tests/ImfTest/res/layout/sample_edit_text.xml
deleted file mode 100644
index 3ff6767..0000000
--- a/tests/ImfTest/res/layout/sample_edit_text.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/samples/SampleCode/res/layout/baseline_1.xml
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:orientation="vertical"
->
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:minHeight="?android:attr/listPreferredItemHeight"
-        android:orientation="horizontal"
-        android:baselineAligned="false"
-        android:gravity="center_vertical"
-    >
-
-        <TextView android:id="@+id/label"
-            android:layout_width="100dip"
-            android:layout_height="wrap_content"
-            android:gravity="right|center_vertical"
-        />
-
-        <EditText android:id="@+id/data"
-            android:layout_width="0dip"
-            android:layout_weight="1"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="8dip"
-        />
-    </LinearLayout>
-
-    <View
-        android:layout_width="match_parent"
-        android:layout_height="1dip"
-        android:background="@android:drawable/divider_horizontal_dark"
-    />
-</LinearLayout>
diff --git a/tests/ImfTest/res/values/config.xml b/tests/ImfTest/res/values/config.xml
deleted file mode 100644
index 5ae40a3..0000000
--- a/tests/ImfTest/res/values/config.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/**
- * Copyright (c) 2009, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); 
- * you may not use this file except in compliance with the License. 
- * You may obtain a copy of the License at 
- *
- *     http://www.apache.org/licenses/LICENSE-2.0 
- *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
- * limitations under the License.
- */
--->
-<resources>
-    <bool name="def_expect_ime_autopop">false</bool>
-</resources>
diff --git a/tests/ImfTest/res/values/strings.xml b/tests/ImfTest/res/values/strings.xml
deleted file mode 100644
index fc87480..0000000
--- a/tests/ImfTest/res/values/strings.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2008, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- Strings for sample activities -->
-    <string name="normal_edit_text_label">Normal</string>
-    <string name="uri_edit_text_label">Uri</string>
-    <string name="email_address_edit_text_label">Email Address</string>
-    <string name="email_subject_edit_text_label">Email Subject</string>
-    <string name="email_content_edit_text_label">Email Content</string>
-    <string name="person_name_edit_text_label">Person Name</string>
-    <string name="postal_address_edit_text_label">Postal Address</string>
-    <string name="password_edit_text_label">Password</string>
-    <string name="search_string_edit_text_label">Search String</string>
-    <string name="web_edit_text_label">Web Edit Text</string>
-    <string name="signed_number_edit_text_label">Signed Number</string>
-    <string name="decimal_number_edit_text_label">Decimal Number</string>
-    <string name="phone_number_edit_text_label">Phone Number</string>
-    <string name="normal_datetime_edit_text_label">Datetime</string>
-    <string name="date_edit_text_label">Date</string>
-    <string name="time_edit_text_label">Time</string>
-    <string name="cap_chars_edit_text_label">Cap Chars</string>
-    <string name="cap_words_edit_text_label">Cap Words</string>
-    <string name="multiline_edit_text_label">Multiline</string>
-    <string name="search_edit_text_label">Search (flag)</string>
-    <string name="cap_sentences_edit_text_label">Cap Sentences</string>
-    <string name="auto_complete_edit_text_label">Auto Complete</string>
-    <string name="auto_correct_edit_text_label">Auto Correct</string>
-    <string name="test_dialog">Test Dialog</string>
-    <string name="open_dialog_scrollable">open scrollable dialog</string>
-    <string name="open_dialog_nonscrollable">open nonscrollable dialog</string>
-    
-    
-</resources>
diff --git a/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityLandscape.java b/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityLandscape.java
deleted file mode 100644
index 6115fd5..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityLandscape.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.provider.MediaStore;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-import android.widget.TextView;
-import android.widget.AutoCompleteTextView;
-import android.widget.ArrayAdapter;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-
-import com.android.internal.R;
-
-/*
- * Activity with AutoCompleteTextView forced to landscape mode
- */
-public class AutoCompleteTextViewActivityLandscape extends Activity 
-{
-   @Override
-   public void onCreate(Bundle savedInstanceState) 
-   {
-       super.onCreate(savedInstanceState);
-    
-       setContentView(R.layout.auto_complete_list);
-
-       ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, 
-               android.R.layout.simple_dropdown_item_1line, COUNTRIES);
-       AutoCompleteTextView textView = findViewById(R.id.edit);
-       textView.setAdapter(adapter);
-   }
-
-   static final String[] COUNTRIES = new String[] {
-   "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra",
-   "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
-   "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan",
-   "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium",
-   "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
-   "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil", "British Indian Ocean Territory",
-   "British Virgin Islands", "Brunei", "Bulgaria", "Burkina Faso", "Burundi",
-   "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde",
-   "Cayman Islands", "Central African Republic", "Chad", "Chile", "China",
-   "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo",
-   "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czechia",
-   "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic",
-   "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea",
-   "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland",
-   "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia",
-   "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar",
-   "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau",
-   "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary",
-   "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica",
-   "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos",
-   "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
-   "Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands",
-   "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova",
-   "Monaco", "Mongolia", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia",
-   "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand",
-   "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas",
-   "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru",
-   "Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar",
-   "Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena",
-   "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon",
-   "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal",
-   "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands",
-   "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea",
-   "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden",
-   "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "The Bahamas",
-   "The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey",
-   "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda",
-   "Ukraine", "United Arab Emirates", "United Kingdom",
-   "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan",
-   "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara",
-   "Yemen", "Yugoslavia", "Zambia", "Zimbabwe"
-   };
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityPortrait.java b/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityPortrait.java
deleted file mode 100644
index 253c50f..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityPortrait.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-import android.widget.TextView;
-import android.widget.AutoCompleteTextView;
-import android.widget.ArrayAdapter;
-
-import com.android.internal.R;
-
-/*
- * Activity with AutoCompleteTextView (Candidate bar should not appear)
- */
-public class AutoCompleteTextViewActivityPortrait extends Activity 
-{
-   @Override
-   public void onCreate(Bundle savedInstanceState) 
-   {
-       super.onCreate(savedInstanceState);
-       
-       setContentView(R.layout.auto_complete_list);
-
-       ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, 
-               android.R.layout.simple_dropdown_item_1line, COUNTRIES);
-       AutoCompleteTextView textView = findViewById(R.id.edit);
-       textView.setAdapter(adapter);
-   }
-
-   static final String[] COUNTRIES = new String[] {
-   "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra",
-   "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
-   "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan",
-   "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium",
-   "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
-   "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil", "British Indian Ocean Territory",
-   "British Virgin Islands", "Brunei", "Bulgaria", "Burkina Faso", "Burundi",
-   "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde",
-   "Cayman Islands", "Central African Republic", "Chad", "Chile", "China",
-   "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo",
-   "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czechia",
-   "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic",
-   "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea",
-   "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland",
-   "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia",
-   "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar",
-   "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau",
-   "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary",
-   "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica",
-   "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos",
-   "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
-   "Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands",
-   "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova",
-   "Monaco", "Mongolia", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia",
-   "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand",
-   "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas",
-   "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru",
-   "Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar",
-   "Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena",
-   "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon",
-   "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal",
-   "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands",
-   "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea",
-   "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden",
-   "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "The Bahamas",
-   "The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey",
-   "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda",
-   "Ukraine", "United Arab Emirates", "United Kingdom",
-   "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan",
-   "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara",
-   "Yemen", "Yugoslavia", "Zambia", "Zimbabwe"
-   };
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScan.java b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScan.java
deleted file mode 100644
index 033082f..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScan.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.imftest.samples;
-
-import com.android.imftest.R;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-
-public class BigEditTextActivityNonScrollablePanScan extends Activity {
-    
-    private View mRootView;
-    private View mDefaultFocusedView;
-    
-    @Override
-    protected void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        
-        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
-        
-        mRootView = new LinearLayout(this);
-        ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
-        mRootView.setLayoutParams(new ViewGroup.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT));
-        
-        View view = getLayoutInflater().inflate(
-                R.layout.full_screen_edit_text, ((LinearLayout) mRootView), false);
-        
-        ((LinearLayout) mRootView).addView(view);
-        
-        mDefaultFocusedView = view.findViewById(R.id.data);
-        
-        setContentView(mRootView);
-    }
-
-    public View getRootView() {
-        return mRootView;
-    }
-    
-    public View getDefaultFocusedView() {
-        return mDefaultFocusedView;
-    }
-
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResize.java b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResize.java
deleted file mode 100644
index 8a16dea..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResize.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.imftest.samples;
-
-import com.android.imftest.R;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-
-public class BigEditTextActivityNonScrollableResize extends Activity {
-    
-    private View mRootView;
-    private View mDefaultFocusedView;
-    
-    @Override
-    protected void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        
-        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
-        
-        mRootView = new LinearLayout(this);
-        ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
-        mRootView.setLayoutParams(new ViewGroup.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT));
-        
-        View view = getLayoutInflater().inflate(
-                R.layout.full_screen_edit_text, ((LinearLayout) mRootView), false);
-        
-        ((LinearLayout) mRootView).addView(view);
-        
-        mDefaultFocusedView = view.findViewById(R.id.data);
-        
-        setContentView(mRootView);
-    }
-
-    public View getRootView() {
-        return mRootView;
-    }
-    
-    public View getDefaultFocusedView() {
-        return mDefaultFocusedView;
-    }
-
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScan.java b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScan.java
deleted file mode 100644
index b4fdc4c..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScan.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.imftest.samples;
-
-import com.android.imftest.R;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.widget.ScrollView;
-
-public class BigEditTextActivityScrollablePanScan extends Activity {
-    
-    private View mRootView;
-    private View mDefaultFocusedView;
-    private LinearLayout mLayout;
-    
-    @Override
-    protected void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        
-        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
-        
-        mRootView = new ScrollView(this);
-        ((ScrollView) mRootView).setFillViewport(true);
-        mRootView.setLayoutParams(new ViewGroup.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT));
-        
-        mLayout = new LinearLayout(this);
-        mLayout.setOrientation(LinearLayout.VERTICAL);
-        mLayout.setLayoutParams(new ViewGroup.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT));
-        
-        View view = getLayoutInflater().inflate(
-                R.layout.full_screen_edit_text, ((ScrollView) mRootView), false);
-        
-        mLayout.addView(view);
-        
-        ((ScrollView) mRootView).addView(mLayout);
-        mDefaultFocusedView = view.findViewById(R.id.data);
-        
-        setContentView(mRootView);
-    }
-
-    public View getRootView() {
-        return mRootView;
-    }
-    
-    public View getDefaultFocusedView() {
-        return mDefaultFocusedView;
-    }
-
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollableResize.java b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollableResize.java
deleted file mode 100644
index 757b6b5..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollableResize.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.imftest.samples;
-
-import com.android.imftest.R;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.widget.ScrollView;
-
-public class BigEditTextActivityScrollableResize extends Activity {
-    
-    private View mRootView;
-    private View mDefaultFocusedView;
-    private LinearLayout mLayout;
-    
-    @Override
-    protected void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        
-        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
-        
-        mRootView = new ScrollView(this);
-        ((ScrollView) mRootView).setFillViewport(true);
-        mRootView.setLayoutParams(new ViewGroup.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT));
-        
-        mLayout = new LinearLayout(this);
-        mLayout.setOrientation(LinearLayout.VERTICAL);
-        mLayout.setLayoutParams(new ViewGroup.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT));
-        
-        View view = getLayoutInflater().inflate(
-                R.layout.full_screen_edit_text, ((ScrollView) mRootView), false);
-        
-        mLayout.addView(view);
-        
-        ((ScrollView) mRootView).addView(mLayout);
-        mDefaultFocusedView = view.findViewById(R.id.data);
-        
-        setContentView(mRootView);
-    }
-
-    public View getRootView() {
-        return mRootView;
-    }
-    
-    public View getDefaultFocusedView() {
-        return mDefaultFocusedView;
-    }
-
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityPanScan.java b/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityPanScan.java
deleted file mode 100644
index 91a329d..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityPanScan.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.widget.EditText;
-import android.widget.ScrollView;
-import android.widget.TextView;
-
-import com.android.imftest.R;
-
-/*
- * Activity with EditText at the bottom (Pan&Scan)
- */
-public class BottomEditTextActivityPanScan extends Activity 
-{
-    private View mRootView;
-    private View mDefaultFocusedView;
-    
-    @Override
-    public void onCreate(Bundle savedInstanceState) 
-    {
-        super.onCreate(savedInstanceState);
-        
-        mRootView = new LinearLayout(this);
-        ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
-        
-        View view = getLayoutInflater().inflate(R.layout.one_edit_text_activity, ((LinearLayout) mRootView), false);
-        mDefaultFocusedView = view.findViewById(R.id.dialog_edit_text);
-        ((LinearLayout) mRootView).addView(view);
-       
-        setContentView(mRootView);
-        this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
-    }  
-
-    public View getRootView() {
-        return mRootView;
-    }
-    
-    public View getDefaultFocusedView() {
-        return mDefaultFocusedView;
-    }
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityResize.java b/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityResize.java
deleted file mode 100644
index c4c41bc..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityResize.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.widget.EditText;
-import android.widget.ScrollView;
-import android.widget.TextView;
-
-import com.android.imftest.R;
-
-/*
- * Activity with EditText at the bottom (Resize)
- */
-public class BottomEditTextActivityResize extends Activity 
-{
-    private View mRootView;
-    private View mDefaultFocusedView;
-    
-    @Override
-    public void onCreate(Bundle savedInstanceState) 
-    {
-        super.onCreate(savedInstanceState);
-        
-        mRootView = new LinearLayout(this);
-        ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
-        
-        View view = getLayoutInflater().inflate(R.layout.one_edit_text_activity, ((LinearLayout) mRootView), false);
-        mDefaultFocusedView = view.findViewById(R.id.dialog_edit_text);
-        ((LinearLayout) mRootView).addView(view);
-       
-        setContentView(mRootView);
-        this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
-    }  
-
-    public View getRootView() {
-        return mRootView;
-    }
-    
-    public View getDefaultFocusedView() {
-        return mDefaultFocusedView;
-    }
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java b/tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java
deleted file mode 100644
index dbaedf9..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.KeyEvent;
-import android.view.View;
-import android.widget.LinearLayout;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-import android.widget.Button;
-import android.widget.TextView;
-
-public class ButtonActivity extends Activity 
-{
-    static boolean mKeyboardIsActive = false;
-    public static final int BUTTON_ID = 0;
-    private View mRootView;
-    
-    @Override
-    public void onCreate(Bundle savedInstanceState) 
-    {
-        super.onCreate(savedInstanceState);
-        final ButtonActivity instance = this;
-             
-        final Button myButton = new Button(this);
-        myButton.setClickable(true);
-        myButton.setText("Keyboard UP!");
-        myButton.setId(BUTTON_ID);
-        myButton.setFocusableInTouchMode(true);
-        myButton.setOnClickListener(new View.OnClickListener()
-        {
-            public void onClick (View v)
-            {
-                InputMethodManager imm = InputMethodManager.getInstance();
-                if (mKeyboardIsActive)
-                {
-                    imm.hideSoftInputFromInputMethod(v.getWindowToken(), 0);
-                    myButton.setText("Keyboard UP!");
-            
-                }
-                else
-                {
-                    myButton.requestFocusFromTouch();
-                    imm.showSoftInput(v, 0);
-                    myButton.setText("Keyboard DOWN!");
-                }
-               
-                mKeyboardIsActive = !mKeyboardIsActive;
-            }
-        });
-            
-       LinearLayout layout = new LinearLayout(this);
-       layout.setOrientation(LinearLayout.VERTICAL);
-       layout.addView(myButton);
-       setContentView(layout);
-       mRootView = layout;
-    }
-    
-    public View getRootView() {
-        return mRootView;
-    }
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/DialogActivity.java b/tests/ImfTest/src/com/android/imftest/samples/DialogActivity.java
deleted file mode 100644
index 3ed0386..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/DialogActivity.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.LinearLayout;
-import android.widget.EditText;
-import android.widget.Button;
-import android.view.LayoutInflater;
-import android.app.Dialog;
-
-public class DialogActivity extends Activity {
-
-    private static final int DIALOG_WITHOUT_EDITTEXT = 0;
-    private static final int DIALOG_WITH_EDITTEXT = 1;
-
-    private LinearLayout mLayout;
-    private LayoutInflater mInflater;
-    private Button mButton1;
-    private Button mButton2;
-    private EditText mEditText;
-
-
-    @Override
-    protected void onCreate(Bundle icicle) 
-    {
-        super.onCreate(icicle);
-
-        mLayout = new LinearLayout(this);
-        mLayout.setOrientation(LinearLayout.VERTICAL);
-        mLayout.setLayoutParams(new ViewGroup.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT));
-
-        mButton1 = new Button(this);
-        mButton1.setText("Dialog WITHOUT EditText");//(R.string.open_dialog_scrollable);
-        mButton1.setOnClickListener(new View.OnClickListener() 
-        {
-            public void onClick(View v) 
-            {
-                showDialog(DIALOG_WITHOUT_EDITTEXT);
-            }
-        });
-
-        mButton2 = new Button(this);
-        mButton2.setText("Dialog WITH EditText");//(R.string.open_dialog_nonscrollable);
-        mButton2.setOnClickListener(new View.OnClickListener() 
-        {
-            public void onClick(View v) 
-            {
-                showDialog(DIALOG_WITH_EDITTEXT);
-            }
-        });
-
-        mEditText = new EditText(this);
-        mLayout.addView(mEditText);
-        mLayout.addView(mButton1);
-        mLayout.addView(mButton2);
-
-        setContentView(mLayout);
-    }
-
-    @Override
-    protected Dialog onCreateDialog(int id) 
-    {
-        switch (id) 
-        {
-            case DIALOG_WITHOUT_EDITTEXT:
-                return createDialog(false);
-            case DIALOG_WITH_EDITTEXT:
-                return createDialog(true);
-        }
-
-        return super.onCreateDialog(id);
-    }
-
-    protected Dialog createDialog(boolean bEditText) 
-    {
-        LinearLayout layout;        
-        layout = new LinearLayout(this);
-        layout.setOrientation(LinearLayout.VERTICAL);
-        
-        if(bEditText)
-        {
-            EditText editText;
-            editText = new EditText(this);
-            layout.addView(editText);
-        }
-        
-        Dialog d = new Dialog(this);
-        d.setTitle("The DIALOG!!!");
-        d.setCancelable(true);
-        d.setContentView(layout);
-        return d;
-    }
-
- }
diff --git a/tests/ImfTest/src/com/android/imftest/samples/EditTextActivityDialog.java b/tests/ImfTest/src/com/android/imftest/samples/EditTextActivityDialog.java
deleted file mode 100644
index 2591b7c..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/EditTextActivityDialog.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.imftest.samples;
-
-import com.android.imftest.R;
-
-import android.app.Activity;
-import android.app.Dialog;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.ScrollView;
-
-public class EditTextActivityDialog extends Activity {
-    
-    private static final int SCROLLABLE_DIALOG_ID = 0;
-    private static final int NONSCROLLABLE_DIALOG_ID = 1;
-    
-    private LinearLayout mLayout;
-    private ScrollView mScrollView;
-    private LayoutInflater mInflater;
-    private Button mButton1;
-    private Button mButton2;
-    
-    
-    @Override
-    protected void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        
-        mLayout = new LinearLayout(this);
-        mLayout.setOrientation(LinearLayout.VERTICAL);
-        mLayout.setLayoutParams(new ViewGroup.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT));
-        
-        mButton1 = new Button(this);
-        mButton1.setText(R.string.open_dialog_scrollable);
-        mButton1.setOnClickListener(new View.OnClickListener() {
-            public void onClick(View v) {
-                showDialog(SCROLLABLE_DIALOG_ID);
-            }
-        });
-        
-        mButton2 = new Button(this);
-        mButton2.setText(R.string.open_dialog_nonscrollable);
-        mButton2.setOnClickListener(new View.OnClickListener() {
-            public void onClick(View v) {
-                showDialog(NONSCROLLABLE_DIALOG_ID);
-            }
-        });
-        
-        mLayout.addView(mButton1);
-        mLayout.addView(mButton2);
-        
-        setContentView(mLayout);
-    }
-    
-    @Override
-    protected Dialog onCreateDialog(int id) {
-        switch (id) {
-            case SCROLLABLE_DIALOG_ID:
-                return createDialog(true);
-            case NONSCROLLABLE_DIALOG_ID:
-                return createDialog(false);
-        }
-
-        return super.onCreateDialog(id);
-    }
-    
-    protected Dialog createDialog(boolean scrollable) {
-        View layout;
-        EditText editText;
-        
-        if (scrollable) {
-            layout = new ScrollView(EditTextActivityDialog.this);
-            ((ScrollView) layout).setMinimumHeight(mLayout.getHeight());
-            
-            ((ScrollView) layout).addView((
-                    LinearLayout) View.inflate(EditTextActivityDialog.this, 
-                    R.layout.dialog_edit_text_no_scroll, null));
-        } else {
-            layout = View.inflate(EditTextActivityDialog.this, 
-                    R.layout.dialog_edit_text_no_scroll, null);
-        }
-        
-        Dialog d = new Dialog(EditTextActivityDialog.this);
-        d.setTitle(getString(R.string.test_dialog));
-        d.setCancelable(true);
-        d.setContentView(layout);
-        return d;
-    }
-
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/InputTypeActivity.java b/tests/ImfTest/src/com/android/imftest/samples/InputTypeActivity.java
deleted file mode 100644
index 299e6bb..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/InputTypeActivity.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.imftest.samples;
-
-import com.android.imftest.R;
-
-import android.app.Activity;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.ScrollView;
-import android.widget.TextView;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.inputmethod.EditorInfo;
-
-public class InputTypeActivity extends Activity {
-
-    private LinearLayout mLayout;
-    private ScrollView mScrollView;
-    private LayoutInflater mInflater;
-    private ViewGroup mParent;
-
-    @Override
-    protected void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        mScrollView = new ScrollView(this);
-        
-        mLayout = new LinearLayout(this);
-        mLayout.setOrientation(LinearLayout.VERTICAL);
-        mLayout.setLayoutParams(new ViewGroup.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT));
-
-        mInflater = getLayoutInflater();
-        mParent = mLayout;
-        
-        /* Normal Edit Text */
-        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL, 
-                R.string.normal_edit_text_label));
-        
-        /* Normal Edit Text w/Cap Chars Flag*/
-        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_CAP_CHARACTERS, 
-                R.string.cap_chars_edit_text_label));
-        
-        /* Normal Edit Text w/Cap Words Flag*/
-        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS, 
-                R.string.cap_words_edit_text_label));
-        
-        /* Normal Edit Text w/Cap Multiline Flag */
-        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE, 
-                R.string.multiline_edit_text_label));
-        
-        /* Normal Edit Text w/Cap Sentences Flag */
-        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES, 
-                R.string.cap_sentences_edit_text_label));
-        
-        /* Normal Edit Text w/Auto-complete Flag */
-        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE, 
-                R.string.auto_complete_edit_text_label));
-        
-        /* Normal Edit Text w/Auto-correct Flag */
-        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT, 
-                R.string.auto_correct_edit_text_label));
-        
-        /* Uri Edit Text */
-        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_URI, 
-                R.string.uri_edit_text_label));
-        
-        /* Email Address Edit Text */
-        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS, 
-                R.string.email_address_edit_text_label));
-        
-        /* Email Subject Text */
-        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_EMAIL_SUBJECT, 
-                R.string.email_subject_edit_text_label));
-        
-        /* Email Content Edit Text */
-        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_LONG_MESSAGE, 
-                R.string.email_content_edit_text_label));
-        
-        /* Person Name Edit Text */
-        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_PERSON_NAME, 
-                R.string.person_name_edit_text_label));
-        
-        /* Postal Address Edit Text */
-        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_POSTAL_ADDRESS, 
-                R.string.postal_address_edit_text_label));
-        
-        /* Password Edit Text */
-        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_PASSWORD, 
-                R.string.password_edit_text_label));
-        
-        /* Web Edit Text */
-        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT, 
-                R.string.web_edit_text_label));
-        
-        /* Signed Number Edit Text */
-        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_NUMBER|EditorInfo.TYPE_NUMBER_FLAG_SIGNED, 
-                R.string.signed_number_edit_text_label));
-        
-        /* Decimal Number Edit Text */
-        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_NUMBER|EditorInfo.TYPE_NUMBER_FLAG_DECIMAL, 
-                R.string.decimal_number_edit_text_label));
-        
-        /* Phone Number Edit Text */
-        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_PHONE, 
-                R.string.phone_number_edit_text_label));
-        
-        /* Normal Datetime Edit Text */
-        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_DATETIME|EditorInfo.TYPE_DATETIME_VARIATION_NORMAL, 
-                R.string.normal_datetime_edit_text_label));
-        
-        /* Date Edit Text */
-        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_DATETIME|EditorInfo.TYPE_DATETIME_VARIATION_DATE, 
-                R.string.date_edit_text_label));
-        
-        /* Time Edit Text */
-        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_DATETIME|EditorInfo.TYPE_DATETIME_VARIATION_TIME, 
-                R.string.time_edit_text_label));
-            
-        mScrollView.addView(mLayout);
-        setContentView(mScrollView);
-    }
-    
-    private View buildEntryView(int inputType, int label) {
-
-        
-        View view = mInflater.inflate(R.layout.sample_edit_text, mParent, false);
-        
-        EditText editText = (EditText) view.findViewById(R.id.data);
-        editText.setInputType(inputType);
-        
-        TextView textView = (TextView) view.findViewById(R.id.label);
-        textView.setText(label);
-        
-        return view;
-    }
-
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScan.java b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScan.java
deleted file mode 100644
index 646e480..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScan.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-import android.widget.Button;
-import android.widget.TextView;
-import android.widget.ScrollView;
-
-import com.android.internal.R;
-
-/*
- * Full screen of EditTexts (Non-Scrollable, Pan&Scan)
- */
-public class ManyEditTextActivityNoScrollPanScan extends Activity 
-{
-    public static final int NUM_EDIT_TEXTS = 9;
-
-    private View mRootView;
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) 
-    {
-        super.onCreate(savedInstanceState);
-
-        mRootView = new LinearLayout(this);
-        ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
-
-        for (int i=0; i<NUM_EDIT_TEXTS; i++) 
-        {
-            final EditText editText = new EditText(this);
-            editText.setText(String.valueOf(i));
-            editText.setId(i);
-            ((LinearLayout) mRootView).addView(editText);
-        }
-        setContentView(mRootView);
-        this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
-    }  
-
-    public View getRootView() {
-        return mRootView;
-    }
-
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScan.java b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScan.java
deleted file mode 100644
index 0387e1e..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScan.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-import android.widget.Button;
-import android.widget.TextView;
-import android.widget.ScrollView;
-
-import com.android.internal.R;
-
-/*
- * Full screen of EditTexts (Scrollable, Pan&Scan)
- */
-public class ManyEditTextActivityScrollPanScan extends Activity 
-{
-    public static final int NUM_EDIT_TEXTS = 12;
-
-    private View mRootView;
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) 
-    {
-        super.onCreate(savedInstanceState);
-        mRootView = new ScrollView(this);
-
-        LinearLayout layout = new LinearLayout(this);
-        layout.setOrientation(LinearLayout.VERTICAL);
-
-        for (int i=0; i<NUM_EDIT_TEXTS; i++) 
-        {
-            final EditText editText = new EditText(this);
-            editText.setText(String.valueOf(i));
-            editText.setId(i);
-            layout.addView(editText);
-        }
-
-        ((ScrollView) mRootView).addView(layout);
-        setContentView(mRootView);
-        this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
-    }   
-
-    public View getRootView() {
-        return mRootView;
-    }
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollResize.java b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollResize.java
deleted file mode 100644
index 7793b55..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollResize.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.View;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.widget.EditText;
-import android.widget.ScrollView;
-
-/*
- * Full screen of EditTexts (Scrollable, Resize)
- */
-public class ManyEditTextActivityScrollResize extends Activity 
-{
-    public static final int NUM_EDIT_TEXTS = 12;
-    
-    private View mRootView;
-    
-    @Override
-    public void onCreate(Bundle savedInstanceState) 
-    {
-        super.onCreate(savedInstanceState);
-        mRootView = new ScrollView(this);
-       
-        LinearLayout layout = new LinearLayout(this);
-        layout.setOrientation(LinearLayout.VERTICAL);
-       
-        for (int i=0; i<NUM_EDIT_TEXTS; i++) 
-        {
-            final EditText editText = new EditText(this);
-            editText.setText(String.valueOf(i));
-            editText.setId(i);
-            layout.addView(editText);
-        }
-
-        ((ScrollView) mRootView).addView(layout);
-        setContentView(mRootView);
-        this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
-    }  
-
-    public View getRootView() {
-        return mRootView;
-    } 
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivityNotSelected.java b/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivityNotSelected.java
deleted file mode 100644
index c4be21c..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivityNotSelected.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.os.Debug;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-import android.widget.Button;
-import android.widget.TextView;
-import android.widget.ScrollView;
-
-import com.android.internal.R;
-
-/*
- * Activity with non-EditText view selected initially
- */
-public class OneEditTextActivityNotSelected extends Activity 
-{
-    private View mRootView;
-    private View mDefaultFocusedView;
-    
-    @Override
-    public void onCreate(Bundle savedInstanceState) 
-    {
-        super.onCreate(savedInstanceState);
-
-        LinearLayout layout = new LinearLayout(this);
-        layout.setOrientation(LinearLayout.VERTICAL);
-        mRootView = new ScrollView(this);
-
-        EditText editText = new EditText(this);
-        Button button = new Button(this);
-        button.setText("The focus is here.");
-        button.setFocusableInTouchMode(true);
-        button.requestFocus();
-        mDefaultFocusedView = button;
-        layout.addView(button);
-        layout.addView(editText);
-
-        ((ScrollView) mRootView).addView(layout);
-        setContentView(mRootView);
-    }  
-
-    public View getRootView() {
-        return mRootView;
-    }
-    
-    public View getDefaultFocusedView() {
-        return mDefaultFocusedView;
-    }
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java b/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java
deleted file mode 100644
index 64882aa..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-import android.widget.Button;
-import android.widget.TextView;
-import android.widget.ScrollView;
-
-import com.android.internal.R;
-
-/*
- * Activity with EditText selected initially
- */
-public class OneEditTextActivitySelected extends Activity 
-{
-    private View mRootView;
-    private View mDefaultFocusedView;
-    
-    @Override
-    public void onCreate(Bundle savedInstanceState) 
-    {
-        super.onCreate(savedInstanceState);
-
-        LinearLayout layout = new LinearLayout(this);
-        layout.setOrientation(LinearLayout.VERTICAL);
-        mRootView = new ScrollView(this);
-        
-        EditText editText = new EditText(this);
-        editText.requestFocus();
-        mDefaultFocusedView = editText;
-        layout.addView(editText);
-
-        ((ScrollView) mRootView).addView(layout);
-        setContentView(mRootView);
-        
-        // set to resize so IME is always shown (and also so
-        // ImfBaseTestCase#destructiveCheckImeInitialState thinks it should always be shown
-        this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
-    }
-
-    public View getRootView() {
-        return mRootView;
-    }
-    
-    public View getDefaultFocusedView() {
-        return mDefaultFocusedView;
-    }
-}
diff --git a/tests/ImfTest/tests/Android.mk b/tests/ImfTest/tests/Android.mk
deleted file mode 100644
index 14186d7..0000000
--- a/tests/ImfTest/tests/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-# Include all test java files.
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
-LOCAL_STATIC_JAVA_LIBRARIES := junit
-
-LOCAL_PACKAGE_NAME := ImfTestTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_INSTRUMENTATION_FOR := ImfTest
-
-include $(BUILD_PACKAGE)
diff --git a/tests/ImfTest/tests/AndroidManifest.xml b/tests/ImfTest/tests/AndroidManifest.xml
deleted file mode 100644
index c02fa0b..0000000
--- a/tests/ImfTest/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.imftest.tests">
-
-    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
-
-    <application>
-        <uses-library android:name="android.test.runner" />
-    </application>
-
-    <!--
-    This declares that this app uses the instrumentation test runner targeting
-    the package of com.android.imftest.  To run the tests use the command:
-    "adb shell am instrument -w com.android.imftest.tests/android.test.InstrumentationTestRunner"
-    -->
-    <instrumentation android:name="android.test.InstrumentationTestRunner"
-                     android:targetPackage="com.android.imftest"
-                     android:label="imf tests"/>
-
-</manifest>
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScanTests.java
deleted file mode 100644
index 2db11c5..0000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScanTests.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.View;
-
-import com.android.imftest.R;
-
-
-public class BigEditTextActivityNonScrollablePanScanTests extends ImfBaseTestCase<BigEditTextActivityNonScrollablePanScan> {
-
-    public final String TAG = "BigEditTextActivityNonScrollablePanScanTests";
-    
-    public BigEditTextActivityNonScrollablePanScanTests() {
-        super(BigEditTextActivityNonScrollablePanScan.class);
-    }
-    
-    @LargeTest
-    public void testAppAdjustmentPanScan() {
-        // Give the IME 2 seconds to appear.
-        pause(2000);
-        
-        View rootView = ((BigEditTextActivityNonScrollablePanScan) mTargetActivity).getRootView();
-        View servedView = ((BigEditTextActivityNonScrollablePanScan) mTargetActivity).getDefaultFocusedView();
-            
-        assertNotNull(rootView);
-        assertNotNull(servedView);
-        
-        destructiveCheckImeInitialState(rootView, servedView);
-        
-        verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
-    }
-    
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResizeTests.java
deleted file mode 100644
index 1050794..0000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResizeTests.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.View;
-
-import com.android.imftest.R;
-
-
-public class BigEditTextActivityNonScrollableResizeTests extends ImfBaseTestCase<BigEditTextActivityNonScrollableResize> {
-
-    public final String TAG = "BigEditTextActivityNonScrollableResizeTests";
-    
-    public BigEditTextActivityNonScrollableResizeTests() {
-        super(BigEditTextActivityNonScrollableResize.class);
-    }
-    
-    @LargeTest
-    public void testAppAdjustmentPanScan() {       // Give the IME 2 seconds to appear.
-        pause(2000);
-        
-        View rootView = ((BigEditTextActivityNonScrollableResize) mTargetActivity).getRootView();
-        View servedView = ((BigEditTextActivityNonScrollableResize) mTargetActivity).getDefaultFocusedView();
-         
-        assertNotNull(rootView);
-        assertNotNull(servedView);
-        
-        destructiveCheckImeInitialState(rootView, servedView);
-            
-        verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
-    }
-    
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScanTests.java
deleted file mode 100644
index 1e848b0..0000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScanTests.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.View;
-
-import com.android.imftest.R;
-
-
-public class BigEditTextActivityScrollablePanScanTests extends ImfBaseTestCase<BigEditTextActivityScrollablePanScan> {
-
-    public final String TAG = "BigEditTextActivityScrollablePanScanTests";
-    
-    public BigEditTextActivityScrollablePanScanTests() {
-        super(BigEditTextActivityScrollablePanScan.class);
-    }
-    
-    @LargeTest
-    public void testAppAdjustmentPanScan() {       // Give the IME 2 seconds to appear.
-        pause(2000);
-        
-        View rootView = ((BigEditTextActivityScrollablePanScan) mTargetActivity).getRootView();
-        View servedView = ((BigEditTextActivityScrollablePanScan) mTargetActivity).getDefaultFocusedView();
-         
-        assertNotNull(rootView);
-        assertNotNull(servedView);
-        
-        destructiveCheckImeInitialState(rootView, servedView);
-            
-        verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
-    }
-    
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollableResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollableResizeTests.java
deleted file mode 100644
index de607d6..0000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollableResizeTests.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.View;
-
-import com.android.imftest.R;
-
-
-public class BigEditTextActivityScrollableResizeTests extends ImfBaseTestCase<BigEditTextActivityScrollableResize> {
-
-    public final String TAG = "BigEditTextActivityScrollableResizeTests";
-    
-    public BigEditTextActivityScrollableResizeTests() {
-        super(BigEditTextActivityScrollableResize.class);
-    }
-    
-    @LargeTest
-    public void testAppAdjustmentPanScan() {       
-        // Give the IME 2 seconds to appear.
-        pause(2000);
-        
-        View rootView = ((BigEditTextActivityScrollableResize) mTargetActivity).getRootView();
-        View servedView = ((BigEditTextActivityScrollableResize) mTargetActivity).getDefaultFocusedView();
-          
-        assertNotNull(rootView);
-        assertNotNull(servedView);
-        
-        destructiveCheckImeInitialState(rootView, servedView);
-            
-        verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
-    }
-    
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityPanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityPanScanTests.java
deleted file mode 100644
index c521905..0000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityPanScanTests.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.View;
-
-import com.android.imftest.R;
-
-
-public class BottomEditTextActivityPanScanTests extends ImfBaseTestCase<BottomEditTextActivityPanScan> {
-
-    public final String TAG = "BottomEditTextActivityPanScanTests";
-    
-    public BottomEditTextActivityPanScanTests() {
-        super(BottomEditTextActivityPanScan.class);
-    }
-    
-    @LargeTest
-    public void testAppAdjustmentPanScan() {
-        // Give the IME 2 seconds to appear.
-        pause(2000);
-        
-        View rootView = ((BottomEditTextActivityPanScan) mTargetActivity).getRootView();
-        View servedView = ((BottomEditTextActivityPanScan) mTargetActivity).getDefaultFocusedView();
-        
-        assertNotNull(rootView);
-        assertNotNull(servedView);
-        
-        destructiveCheckImeInitialState(rootView, servedView);
-        
-        verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
-    }
-    
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityResizeTests.java
deleted file mode 100644
index 9a69fd5..0000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityResizeTests.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.View;
-
-import com.android.imftest.R;
-
-
-public class BottomEditTextActivityResizeTests extends ImfBaseTestCase<BottomEditTextActivityResize> {
-
-    public final String TAG = "BottomEditTextActivityResizeTests";
-    
-    public BottomEditTextActivityResizeTests() {
-        super(BottomEditTextActivityResize.class);
-    }
-    
-    @LargeTest
-    public void testAppAdjustmentResize() {
-        // Give the IME 2 seconds to appear.
-        pause(2000);
-        
-        View rootView = ((BottomEditTextActivityResize) mTargetActivity).getRootView();
-        View servedView = ((BottomEditTextActivityResize) mTargetActivity).getDefaultFocusedView();
-        
-        assertNotNull(rootView);
-        assertNotNull(servedView);
-        
-        destructiveCheckImeInitialState(rootView, servedView);
-        
-        verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
-    }
-    
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ButtonActivityTest.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ButtonActivityTest.java
deleted file mode 100644
index f6f97b5..0000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/ButtonActivityTest.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.KeyEvent;
-import android.widget.Button;
-
-
-public class ButtonActivityTest extends ImfBaseTestCase<ButtonActivity> {
-
-    final public String TAG = "ButtonActivityTest";
-    
-    public ButtonActivityTest() {
-        super(ButtonActivity.class);
-    }
-
-    @LargeTest
-    public void testButtonActivatesIme() {
-       
-        final Button button = (Button) mTargetActivity.findViewById(ButtonActivity.BUTTON_ID);
-        
-        // Push button
-        // Bring the target EditText into focus.
-        mTargetActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                button.requestFocus();
-            }
-        });
-        
-        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
-        
-        // Give it a couple seconds
-        pause(2000);
-        
-        // We should have initialized imm.mServedView and imm.mCurrentTextBoxAttribute
-        assertTrue(mImm.isActive());
-        // imm.mServedInputConnection should be null since Button doesn't override onCreateInputConnection().
-        assertFalse(mImm.isAcceptingText());
-        
-        destructiveCheckImeInitialState(mTargetActivity.getRootView(), button);
-        
-    }
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java
deleted file mode 100644
index 32f80a3..0000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.imftest.samples;
-
-import android.app.Activity;
-import android.app.KeyguardManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Configuration;
-import android.os.SystemClock;
-import android.test.InstrumentationTestCase;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.inputmethod.InputMethodManager;
-
-import com.android.imftest.R;
-
-public abstract class ImfBaseTestCase<T extends Activity> extends InstrumentationTestCase {
-
-    /*
-     * The amount of time we are willing to wait for the IME to appear after a user action
-     * before we give up and fail the test.
-     */
-    public final long WAIT_FOR_IME = 5000;
-
-    /*
-     * Unfortunately there is now way for us to know how tall the IME is,
-     * so we have to hard code a minimum and maximum value.
-     */
-    public final int IME_MIN_HEIGHT = 150;
-    public final int IME_MAX_HEIGHT = 300;
-
-    protected InputMethodManager mImm;
-    protected T mTargetActivity;
-    protected boolean mExpectAutoPop;
-    private Class<T> mTargetActivityClass;
-
-    public ImfBaseTestCase(Class<T> activityClass) {
-        mTargetActivityClass = activityClass;
-    }
-
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        final String packageName = getInstrumentation().getTargetContext().getPackageName();
-        Intent intent = new Intent(Intent.ACTION_MAIN);
-        intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
-        mTargetActivity = launchActivityWithIntent(packageName, mTargetActivityClass, intent);
-        // expect ime to auto pop up if device has no hard keyboard
-        int keyboardType = mTargetActivity.getResources().getConfiguration().keyboard;
-        mExpectAutoPop = (keyboardType  == Configuration.KEYBOARD_NOKEYS ||
-                keyboardType == Configuration.KEYBOARD_UNDEFINED);
-
-        mImm = InputMethodManager.getInstance();
-
-        KeyguardManager keyguardManager =
-            (KeyguardManager) getInstrumentation().getContext().getSystemService(
-                    Context.KEYGUARD_SERVICE);
-        keyguardManager.newKeyguardLock("imftest").disableKeyguard();
-    }
-    
-    // Utility test methods
-    public void verifyEditTextAdjustment(final View editText, int rootViewHeight) {
-
-        int[] origLocation = new int[2];
-        int[] newLocation = new int[2];
-
-        // Tell the keyboard to go away.
-        mImm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
-
-        // Bring the target EditText into focus.
-        mTargetActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                editText.requestFocus();
-            }
-        });
-
-        // Get the original location of the EditText.
-        editText.getLocationOnScreen(origLocation);
-
-        // Tap the EditText to bring up the IME.
-        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
-
-        // Wait until the EditText pops above the IME or until we hit the timeout.
-        editText.getLocationOnScreen(newLocation);
-        long timeoutTime = SystemClock.uptimeMillis() + WAIT_FOR_IME;
-        while (newLocation[1] > rootViewHeight - IME_MIN_HEIGHT && SystemClock.uptimeMillis() < timeoutTime) {
-            editText.getLocationOnScreen(newLocation);
-            pause(100);
-        }
-
-        assertTrue(newLocation[1] <= rootViewHeight - IME_MIN_HEIGHT);
-
-        // Tell the keyboard to go away.
-        mImm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
-    }
-
-    public void destructiveCheckImeInitialState(View rootView, View servedView) {
-        int windowSoftInputMode = mTargetActivity.getWindow().getAttributes().softInputMode;
-        int adjustMode = windowSoftInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
-        if (mExpectAutoPop && adjustMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) {
-            assertTrue(destructiveCheckImeUp(rootView, servedView));
-        } else {
-            assertFalse(destructiveCheckImeUp(rootView, servedView));
-        }
-    }
-
-    public boolean destructiveCheckImeUp(View rootView, View servedView) {
-        int origHeight;
-        int newHeight;
-
-        origHeight = rootView.getHeight();
-
-        // Tell the keyboard to go away.
-        mImm.hideSoftInputFromWindow(servedView.getWindowToken(), 0);
-
-        // Give it five seconds to adjust
-        newHeight = rootView.getHeight();
-        long timeoutTime = SystemClock.uptimeMillis() + WAIT_FOR_IME;
-        while (Math.abs(newHeight - origHeight) < IME_MIN_HEIGHT && SystemClock.uptimeMillis() < timeoutTime) {
-            newHeight = rootView.getHeight();
-        }
-
-        return (Math.abs(origHeight - newHeight) >= IME_MIN_HEIGHT);
-    }
-
-    void pause(int millis) {
-        try {
-            Thread.sleep(millis);
-        } catch (InterruptedException e) {
-        }
-    }
-
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityBaseTestCase.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityBaseTestCase.java
deleted file mode 100644
index 278efb1..0000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityBaseTestCase.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.imftest.samples;
-
-import android.app.Activity;
-import android.widget.EditText;
-
-
-public abstract class ManyEditTextActivityBaseTestCase<T extends Activity> extends ImfBaseTestCase<T> {
-  
-    public ManyEditTextActivityBaseTestCase(Class<T> activityClass){
-        super(activityClass);
-    }
-
-    public abstract void testAllEditTextsAdjust();
-
-    public void verifyAllEditTextAdjustment(int numEditTexts, int rootViewHeight) {
-
-        for (int i = 0; i < numEditTexts; i++) {
-            final EditText lastEditText = (EditText) mTargetActivity.findViewById(i);
-            verifyEditTextAdjustment(lastEditText, rootViewHeight);
-        }
-
-    }
-
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScanTests.java
deleted file mode 100644
index 4f8d14e..0000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScanTests.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-
-
-public class ManyEditTextActivityNoScrollPanScanTests extends ManyEditTextActivityBaseTestCase<ManyEditTextActivityNoScrollPanScan> {
-
-    public final String TAG = "ManyEditTextActivityNoScrollPanScanTests";
-    
-    public ManyEditTextActivityNoScrollPanScanTests() {
-        super(ManyEditTextActivityNoScrollPanScan.class);
-    }
-
-   
-    @LargeTest
-    public void testAllEditTextsAdjust() {
-        verifyAllEditTextAdjustment(mTargetActivity.NUM_EDIT_TEXTS, 
-                mTargetActivity.getRootView().getMeasuredHeight());
-    }
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScanTests.java
deleted file mode 100644
index 7f98f7f..0000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScanTests.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-
-
-public class ManyEditTextActivityScrollPanScanTests extends ManyEditTextActivityBaseTestCase<ManyEditTextActivityScrollPanScan> {
-
-    public final String TAG = "ManyEditTextActivityScrollPanScanTests";
-    
-    
-    public ManyEditTextActivityScrollPanScanTests() {
-        super(ManyEditTextActivityScrollPanScan.class);
-    }
-    
-    @LargeTest
-    public void testAllEditTextsAdjust() {
-        verifyAllEditTextAdjustment(mTargetActivity.NUM_EDIT_TEXTS, 
-                mTargetActivity.getRootView().getMeasuredHeight());
-    }
-
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollResizeTests.java
deleted file mode 100644
index 68dae87..0000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollResizeTests.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-
-
-public class ManyEditTextActivityScrollResizeTests extends ManyEditTextActivityBaseTestCase<ManyEditTextActivityScrollResize> {
-
-    public final String TAG = "ManyEditTextActivityScrollResizeTests";
-    
-    
-    public ManyEditTextActivityScrollResizeTests() {
-        super(ManyEditTextActivityScrollResize.class);
-    }
-
-    @LargeTest
-    public void testAllEditTextsAdjust() {
-        verifyAllEditTextAdjustment(mTargetActivity.NUM_EDIT_TEXTS, 
-                mTargetActivity.getRootView().getMeasuredHeight());
-    }
-
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivityNotSelectedTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivityNotSelectedTests.java
deleted file mode 100644
index 6147d3c..0000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivityNotSelectedTests.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.View;
-
-
-public class OneEditTextActivityNotSelectedTests extends ImfBaseTestCase<OneEditTextActivityNotSelected> {
-
-    public final String TAG = "OneEditTextActivityNotSelectedTests";
-    
-    public OneEditTextActivityNotSelectedTests() {
-        super(OneEditTextActivityNotSelected.class);
-    }
-    
-    @LargeTest
-    public void testSoftKeyboardNoAutoPop() {
-        
-        // Give the IME 2 seconds to appear.
-        pause(2000);
-        
-        assertFalse(mImm.isAcceptingText());
-        
-        View rootView = ((OneEditTextActivityNotSelected) mTargetActivity).getRootView();
-        View servedView = ((OneEditTextActivityNotSelected) mTargetActivity).getDefaultFocusedView();
-        
-        assertNotNull(rootView);
-        assertNotNull(servedView);
-        
-        destructiveCheckImeInitialState(rootView, servedView);
-        
-        verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
-    }
-    
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivitySelectedTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivitySelectedTests.java
deleted file mode 100644
index 42fcd66..0000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivitySelectedTests.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.imftest.samples;
-
-import com.android.imftest.R;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.KeyEvent;
-import android.view.View;
-
-
-public class OneEditTextActivitySelectedTests extends ImfBaseTestCase<OneEditTextActivitySelected> {
-
-    public final String TAG = "OneEditTextActivitySelectedTests";
-    
-    public OneEditTextActivitySelectedTests() {
-        super(OneEditTextActivitySelected.class);
-    }
-    
-    @LargeTest
-    public void testSoftKeyboardAutoPop() {
-        
-        // Give the IME 2 seconds to appear.
-        pause(2000);
-        
-        assertTrue(mImm.isAcceptingText());
-        
-        View rootView = ((OneEditTextActivitySelected) mTargetActivity).getRootView();
-        View servedView = ((OneEditTextActivitySelected) mTargetActivity).getDefaultFocusedView();
-        
-        assertNotNull(rootView);
-        assertNotNull(servedView);
-        
-        destructiveCheckImeInitialState(rootView, servedView);
-        
-        verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
-    }
-    
-}
diff --git a/tests/NativeProcessesMemoryTest/Android.bp b/tests/NativeProcessesMemoryTest/Android.bp
new file mode 100644
index 0000000..f2625bf
--- /dev/null
+++ b/tests/NativeProcessesMemoryTest/Android.bp
@@ -0,0 +1,21 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+java_test_host {
+    name: "native-processes-memory-test",
+    srcs: ["src/**/*.java"],
+
+    libs: ["tradefed"],
+    test_suites: ["general-tests"],
+}
diff --git a/packages/SettingsLib/res/layout/restricted_icon.xml b/tests/NativeProcessesMemoryTest/AndroidTest.xml
similarity index 60%
copy from packages/SettingsLib/res/layout/restricted_icon.xml
copy to tests/NativeProcessesMemoryTest/AndroidTest.xml
index 724a524..0f326fd 100644
--- a/packages/SettingsLib/res/layout/restricted_icon.xml
+++ b/tests/NativeProcessesMemoryTest/AndroidTest.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- Copyright (C) 2018 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -13,8 +13,9 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/restricted_icon"
-    android:layout_width="@dimen/restricted_icon_size"
-    android:layout_height="@dimen/restricted_icon_size"
-    android:src="@drawable/ic_info" />
\ No newline at end of file
+<configuration description="Runs the native processes memory tests">
+    <option name="test-suite-tag" value="native-processes-memory-test" />
+    <test class="com.android.tradefed.testtype.HostTest" >
+        <option name="class" value="com.android.tests.nativeprocesses.NativeProcessesMemoryTest" />
+    </test>
+</configuration>
diff --git a/tests/NativeProcessesMemoryTest/src/com/android/tests/nativeprocesses/NativeProcessesMemoryTest.java b/tests/NativeProcessesMemoryTest/src/com/android/tests/nativeprocesses/NativeProcessesMemoryTest.java
new file mode 100644
index 0000000..c86f06e
--- /dev/null
+++ b/tests/NativeProcessesMemoryTest/src/com/android/tests/nativeprocesses/NativeProcessesMemoryTest.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.tests.nativeprocesses;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.result.ByteArrayInputStreamSource;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.result.LogDataType;
+import com.android.tradefed.result.TestDescription;
+import com.android.tradefed.testtype.IDeviceTest;
+import com.android.tradefed.testtype.IRemoteTest;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.InputMismatchException;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Scanner;
+
+/**
+ * Test to gather native processes count and memory usage.
+ *
+ * Native processes are parsed from dumpsys meminfo --oom -c
+ *
+ * <pre>
+ * time,35857009,35857009
+ * oom,native,331721,N/A
+ * proc,native,init,1,2715,N/A,e
+ * proc,native,init,445,1492,N/A,e
+ * ...
+ * </pre>
+ *
+ * For each native process we also look at its showmap output, and gather the PSS, VSS, and RSS.
+ * The showmap output is also saved to test logs.
+ *
+ * The metrics reported are:
+ *
+ * <pre>
+ *   - number of native processes
+ *   - total memory use of native processes
+ *   - memory usage of each native process (one measurement for each process)
+ * </pre>
+ */
+public class NativeProcessesMemoryTest implements IDeviceTest, IRemoteTest {
+    // the dumpsys process comes and go as we run this test, changing pids, so ignore it
+    private static final List<String> PROCESSES_TO_IGNORE = Arrays.asList("dumpsys");
+
+    // -c gives us a compact output which is comma separated
+    private static final String DUMPSYS_MEMINFO_OOM_CMD = "dumpsys meminfo --oom -c";
+
+    private static final String SEPARATOR = ",";
+    private static final String LINE_SEPARATOR = "\\n";
+
+    // name of this test run, used for reporting
+    private static final String RUN_NAME = "NativeProcessesTest";
+    // key used to report the number of native processes
+    private static final String NUM_NATIVE_PROCESSES_KEY = "Num_native_processes";
+
+    private final Map<String, String> mNativeProcessToMemory = new HashMap<String, String>();
+    // identity for summing over MemoryMetric
+    private final MemoryMetric mZero = new MemoryMetric(0, 0, 0);
+
+    private ITestDevice mTestDevice;
+    private ITestInvocationListener mListener;
+
+    public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
+        mListener = listener;
+        // showmap requires root, we enable it here for the rest of the test
+        mTestDevice.enableAdbRoot();
+
+        listener.testRunStarted(RUN_NAME, 1 /* testCount */);
+
+        TestDescription testDescription = new TestDescription(getClass().getName(), "run");
+        listener.testStarted(testDescription);
+
+        // process name -> list of pids with that name
+        Map<String, List<String>> nativeProcesses = collectNativeProcesses();
+        sampleAndLogAllProcesses(nativeProcesses);
+
+        // want to also record the number of native processes
+        mNativeProcessToMemory.put(
+                NUM_NATIVE_PROCESSES_KEY, Integer.toString(nativeProcesses.size()));
+
+        listener.testEnded(testDescription, mNativeProcessToMemory);
+        listener.testRunEnded(0, new HashMap<String, String>());
+    }
+
+    /** Samples memory of all processes and logs the memory use. */
+    private void sampleAndLogAllProcesses(Map<String, List<String>> nativeProcesses)
+            throws DeviceNotAvailableException {
+        for (Map.Entry<String, List<String>> entry : nativeProcesses.entrySet()) {
+            String processName = entry.getKey();
+            if (PROCESSES_TO_IGNORE.contains(processName)) {
+                continue;
+            }
+
+            // for all pids associated with this process name, record their memory usage
+            List<MemoryMetric> allMemsForProcess = new ArrayList<>();
+            for (String pid : entry.getValue()) {
+                Optional<MemoryMetric> mem = snapMemoryUsage(processName, pid);
+                if (mem.isPresent()) {
+                    allMemsForProcess.add(mem.get());
+                }
+            }
+
+            // if for some reason a process does not have any MemoryMetric, don't log it
+            if (allMemsForProcess.isEmpty()) {
+                continue;
+            }
+
+            // combine all the memory metrics of process with the same name
+            MemoryMetric combined = allMemsForProcess.stream().reduce(mZero, MemoryMetric::sum);
+            logMemoryMetric(processName, combined);
+        }
+    }
+
+    @Override
+    public void setDevice(ITestDevice device) {
+        mTestDevice = device;
+    }
+
+    @Override
+    public ITestDevice getDevice() {
+        return mTestDevice;
+    }
+
+    /**
+     * Query system for a list of native process.
+     *
+     * @return a map from process name to a list of pids that share the same name
+     */
+    private Map<String, List<String>> collectNativeProcesses() throws DeviceNotAvailableException {
+        HashMap<String, List<String>> nativeProcesses = new HashMap<>();
+        String memInfo = mTestDevice.executeShellCommand(DUMPSYS_MEMINFO_OOM_CMD);
+
+        for (String line : memInfo.split(LINE_SEPARATOR)) {
+            String[] splits = line.split(SEPARATOR);
+            // ignore lines that don't list a native process
+            if (splits.length < 4 || !splits[0].equals("proc") || !splits[1].equals("native")) {
+                continue;
+            }
+
+            String processName = splits[2];
+            String pid = splits[3];
+            if (nativeProcesses.containsKey(processName)) {
+                nativeProcesses.get(processName).add(pid);
+            } else {
+                nativeProcesses.put(processName, new ArrayList<>(Arrays.asList(pid)));
+            }
+        }
+        return nativeProcesses;
+    }
+
+    /** Logs an entire showmap output to the test logs. */
+    private void logShowmap(String label, String showmap) {
+        try (ByteArrayInputStreamSource source =
+                new ByteArrayInputStreamSource(showmap.getBytes())) {
+            mListener.testLog(label + "_showmap", LogDataType.TEXT, source);
+        }
+    }
+
+    /**
+     * Extract VSS, PSS, and RSS from showmap of a process.
+     * The showmap output is also added to test logs.
+     */
+    private Optional<MemoryMetric> snapMemoryUsage(String processName, String pid)
+            throws DeviceNotAvailableException {
+        // TODO(zhin): copied from com.android.tests.sysmem.host.Metrics#sample(), extract?
+        String showmap = mTestDevice.executeShellCommand("showmap " + pid);
+        logShowmap(processName + "_" + pid, showmap);
+
+        // CHECKSTYLE:OFF Generated code
+        // The last lines of the showmap output looks like:
+        // ------- -------- -------- -------- -------- -------- -------- -------- -------- ---- ------------------------------
+        // virtual                     shared   shared  private  private
+        //    size      RSS      PSS    clean    dirty    clean    dirty     swap  swapPSS   # object
+        // -------- -------- -------- -------- -------- -------- -------- -------- -------- ---- ------------------------------
+        //   12848     4240     1543     2852       64       36     1288        0        0  171 TOTAL
+        // CHECKSTYLE:ON Generated code
+        try {
+            int pos = showmap.lastIndexOf("----");
+            Scanner sc = new Scanner(showmap.substring(pos));
+            sc.next();
+            long vss = sc.nextLong();
+            long rss = sc.nextLong();
+            long pss = sc.nextLong();
+            return Optional.of(new MemoryMetric(pss, rss, vss));
+        } catch (InputMismatchException e) {
+            // this might occur if we have transient processes, it was collected earlier,
+            // but by the time we look at showmap the process is gone
+            CLog.e("Unable to parse MemoryMetric from showmap of pid: " + pid + " processName: "
+                    + processName);
+            CLog.e(showmap);
+            return Optional.empty();
+        }
+    }
+
+    /** Logs a MemoryMetric of a process. */
+    private void logMemoryMetric(String processName, MemoryMetric memoryMetric) {
+        mNativeProcessToMemory.put(processName + "_pss", Long.toString(memoryMetric.pss));
+        mNativeProcessToMemory.put(processName + "_rss", Long.toString(memoryMetric.rss));
+        mNativeProcessToMemory.put(processName + "_vss", Long.toString(memoryMetric.vss));
+    }
+
+    /** Container of memory numbers we want to log. */
+    private final class MemoryMetric {
+        final long pss;
+        final long rss;
+        final long vss;
+
+        MemoryMetric(long pss, long rss, long vss) {
+            this.pss = pss;
+            this.rss = rss;
+            this.vss = vss;
+        }
+
+        MemoryMetric sum(MemoryMetric other) {
+            return new MemoryMetric(
+                    pss + other.pss, rss + other.rss, vss + other.vss);
+        }
+    }
+}
diff --git a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Cujs.java b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Cujs.java
index 579d972..6500428 100644
--- a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Cujs.java
+++ b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Cujs.java
@@ -11,33 +11,36 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
  */
 
 package com.android.tests.sysmem.host;
 
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-
 /**
  * Critical user journeys with which to exercise the system, driven from the
  * host.
  */
 public class Cujs {
-    private ITestDevice device;
+    private Device mDevice;
 
-    public Cujs(ITestDevice device) {
-        this.device = device;
+    public Cujs(Device device) {
+        this.mDevice = device;
     }
 
     /**
      * Runs the critical user journeys.
      */
-    public void run() throws DeviceNotAvailableException {
+    public void run() throws TestException {
+        // Do an explicit GC in the system server process as part of the test
+        // case to reduce GC-related sources of noise.
+        // SIGUSR1 = 10 is the magic signal to trigger the GC.
+        int pid = mDevice.getPidForProcess("system_server");
+        mDevice.executeShellCommand("kill -10 " + pid);
+
         // Invoke the Device Cujs instrumentation to run the cujs.
         // TODO: Consider exercising the system in other interesting ways as
         // well.
         String command = "am instrument -w com.android.tests.sysmem.device/.Cujs";
-        device.executeShellCommand(command);
+        mDevice.executeShellCommand(command);
     }
 }
diff --git a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Device.java b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Device.java
new file mode 100644
index 0000000..03503ce
--- /dev/null
+++ b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Device.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tests.sysmem.host;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+
+import java.util.InputMismatchException;
+import java.util.Scanner;
+
+/**
+ * Wrapper around ITestDevice exposing useful device functions.
+ */
+class Device {
+
+    private ITestDevice mDevice;
+
+    Device(ITestDevice device) {
+        mDevice = device;
+    }
+
+    /**
+     * Execute a shell command and return the output as a string.
+     */
+    public String executeShellCommand(String command) throws TestException {
+        try {
+            return mDevice.executeShellCommand(command);
+        } catch (DeviceNotAvailableException e) {
+            throw new TestException(e);
+        }
+    }
+
+    /**
+     * Enable adb root
+     */
+    public void enableAdbRoot() throws TestException {
+        try {
+            mDevice.enableAdbRoot();
+        } catch (DeviceNotAvailableException e) {
+            throw new TestException(e);
+        }
+    }
+
+    /**
+     * Returns the pid for the process with the given name.
+     */
+    public int getPidForProcess(String name) throws TestException {
+        String psout = executeShellCommand("ps -A -o PID,CMD");
+        Scanner sc = new Scanner(psout);
+        try {
+            // ps output is of the form:
+            //  PID CMD
+            //    1 init
+            //    2 kthreadd
+            //    ...
+            // 9693 ps
+            sc.nextLine();
+            while (sc.hasNextLine()) {
+                int pid = sc.nextInt();
+                String cmd = sc.next();
+
+                if (name.equals(cmd)) {
+                    return pid;
+                }
+            }
+        } catch (InputMismatchException e) {
+            throw new TestException("unexpected ps output format: " + psout, e);
+        }
+
+        throw new TestException("failed to get pid for process " + name);
+    }
+}
diff --git a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/MemoryTest.java b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/MemoryTest.java
index bbec065..48b7f39 100644
--- a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/MemoryTest.java
+++ b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/MemoryTest.java
@@ -11,59 +11,64 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
  */
 
 package com.android.tests.sysmem.host;
 
-import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner.TestLogData;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner.TestMetrics;
 import com.android.tradefed.testtype.IDeviceTest;
-import java.io.IOException;
+
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+/**
+ * Runs a system memory test.
+ */
 @RunWith(DeviceJUnit4ClassRunner.class)
 public class MemoryTest implements IDeviceTest {
 
     @Rule public TestMetrics testMetrics = new TestMetrics();
     @Rule public TestLogData testLogs = new TestLogData();
 
-    private ITestDevice testDevice;
-    private int iterations = 0;     // Number of times cujs have been run.
-    private Metrics metrics;
-    private Cujs cujs;
+    private ITestDevice mTestDevice;
+    private int mIterations = 0;     // Number of times cujs have been run.
+    private Metrics mMetrics;
+    private Cujs mCujs;
 
     @Override
-    public void setDevice(ITestDevice device) {
-        testDevice = device;
-        metrics = new Metrics(device, testMetrics, testLogs);
-        cujs = new Cujs(device);
+    public void setDevice(ITestDevice testDevice) {
+        mTestDevice = testDevice;
+        Device device = new Device(testDevice);
+        mMetrics = new Metrics(device, testMetrics, testLogs);
+        mCujs = new Cujs(device);
     }
 
     @Override
     public ITestDevice getDevice() {
-        return testDevice;
+        return mTestDevice;
     }
 
     // Invoke a single iteration of running the cujs.
-    private void runCujs() throws DeviceNotAvailableException {
-        cujs.run();
-        iterations++;
+    private void runCujs() throws TestException {
+        mCujs.run();
+        mIterations++;
     }
 
     // Sample desired memory.
-    private void sample()
-            throws DeviceNotAvailableException, IOException, Metrics.MetricsException {
-        metrics.sample(String.format("%03d", iterations));
+    private void sample() throws TestException {
+        mMetrics.sample(String.format("%03d", mIterations));
     }
 
+    /**
+     * Runs the memory tests.
+     */
     @Test
-    public void run() throws Exception {
+    public void run() throws TestException {
         sample();   // Sample before running cujs
         runCujs();
         sample();   // Sample after first iteration of cujs
diff --git a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Metrics.java b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Metrics.java
index 616983e..b408a81 100644
--- a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Metrics.java
+++ b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Metrics.java
@@ -11,17 +11,16 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
  */
 
 package com.android.tests.sysmem.host;
 
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.result.FileInputStreamSource;
 import com.android.tradefed.result.LogDataType;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner.TestLogData;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner.TestMetrics;
+
 import java.io.File;
 import java.io.IOException;
 import java.io.PrintStream;
@@ -33,22 +32,9 @@
  */
 class Metrics {
 
-    private ITestDevice device;
-    private TestMetrics metrics;
-    private TestLogData logs;
-
-    /**
-     * Exception thrown in case of error sampling metrics.
-     */
-    public static class MetricsException extends Exception {
-        public MetricsException(String msg) {
-            super(msg);
-        }
-
-        MetricsException(String msg, Exception cause) {
-            super(msg, cause);
-        }
-    }
+    private Device mDevice;
+    private TestMetrics mMetrics;
+    private TestLogData mLogs;
 
     /**
      * Constructs a metrics instance that will output high level metrics and
@@ -59,52 +45,26 @@
      * @param metrics where to log the high level metrics when taking a sample
      * @param logs where to log detailed breakdowns when taking a sample
      */
-    public Metrics(ITestDevice device, TestMetrics metrics, TestLogData logs) {
-        this.device = device;
-        this.metrics = metrics;
-        this.logs = logs;
+    Metrics(Device device, TestMetrics metrics, TestLogData logs) {
+        this.mDevice = device;
+        this.mMetrics = metrics;
+        this.mLogs = logs;
     }
 
     /**
      * Writes the given <code>text</code> to a log with the given label.
      */
-    private void logText(String label, String text) throws IOException {
-      File file = File.createTempFile(label, "txt");
-      PrintStream ps = new PrintStream(file);
-      ps.print(text);
-      try (FileInputStreamSource dataStream = new FileInputStreamSource(file)) {
-        logs.addTestLog(label, LogDataType.TEXT, dataStream);
-      }
-    }
-
-    /**
-     * Returns the pid for the process with the given name.
-     */
-    private int getPidForProcess(String name)
-            throws DeviceNotAvailableException, IOException, MetricsException {
-        String psout = device.executeShellCommand("ps -A -o PID,CMD");
-        Scanner sc = new Scanner(psout);
+    private void logText(String label, String text) throws TestException {
         try {
-            // ps output is of the form:
-            //  PID CMD            
-            //    1 init
-            //    2 kthreadd
-            //    ...
-            // 9693 ps
-            sc.nextLine();
-            while (sc.hasNextLine()) {
-                int pid = sc.nextInt();
-                String cmd = sc.next();
-
-                if (name.equals(cmd)) {
-                    return pid;
-                }
+            File file = File.createTempFile(label, "txt");
+            PrintStream ps = new PrintStream(file);
+            ps.print(text);
+            try (FileInputStreamSource dataStream = new FileInputStreamSource(file)) {
+                mLogs.addTestLog(label, LogDataType.TEXT, dataStream);
             }
-        } catch (InputMismatchException e) {
-            throw new MetricsException("unexpected ps output format: " + psout, e);
+        } catch (IOException e) {
+            throw new TestException(e);
         }
-
-        throw new MetricsException("failed to get pid for process " + name);
     }
 
     /**
@@ -115,22 +75,24 @@
      *
      * @param label prefix to use for metrics and logs output for this sample.
      */
-    void sample(String label) throws DeviceNotAvailableException, IOException, MetricsException {
+    void sample(String label) throws TestException {
         // adb root access is required to get showmap
-        device.enableAdbRoot();
+        mDevice.enableAdbRoot();
 
-        int pid = getPidForProcess("system_server");
+        int pid = mDevice.getPidForProcess("system_server");
 
         // Read showmap for system server and add it as a test log
-        String showmap = device.executeShellCommand("showmap " + pid);
+        String showmap = mDevice.executeShellCommand("showmap " + pid);
         logText(label + ".system_server.showmap", showmap);
 
         // Extract VSS, PSS and RSS from the showmap and output them as metrics.
         // The last lines of the showmap output looks something like:
+        // CHECKSTYLE:OFF Generated code
         // virtual                     shared   shared  private  private
         //    size      RSS      PSS    clean    dirty    clean    dirty     swap  swapPSS   # object
         //-------- -------- -------- -------- -------- -------- -------- -------- -------- ---- ------------------------------
         //  928480   113016    24860    87348     7916     3632    14120     1968     1968 1900 TOTAL
+        // CHECKSTYLE:ON Generated code
         try {
             int pos = showmap.lastIndexOf("----");
             Scanner sc = new Scanner(showmap.substring(pos));
@@ -139,16 +101,16 @@
             long rss = sc.nextLong();
             long pss = sc.nextLong();
 
-            metrics.addTestMetric(String.format("%s.system_server.vss", label), Long.toString(vss));
-            metrics.addTestMetric(String.format("%s.system_server.rss", label), Long.toString(rss));
-            metrics.addTestMetric(String.format("%s.system_server.pss", label), Long.toString(pss));
+            mMetrics.addTestMetric(label + ".system_server.vss", Long.toString(vss));
+            mMetrics.addTestMetric(label + ".system_server.rss", Long.toString(rss));
+            mMetrics.addTestMetric(label + ".system_server.pss", Long.toString(pss));
         } catch (InputMismatchException e) {
-            throw new MetricsException("unexpected showmap format", e);
+            throw new TestException("unexpected showmap format", e);
         }
 
         // Run debuggerd -j to get GC stats for system server and add it as a
         // test log
-        String debuggerd = device.executeShellCommand("debuggerd -j " + pid);
+        String debuggerd = mDevice.executeShellCommand("debuggerd -j " + pid);
         logText(label + ".system_server.debuggerd", debuggerd);
 
         // TODO: Experiment with other additional metrics.
diff --git a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/TestException.java b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/TestException.java
new file mode 100644
index 0000000..dc3b68f
--- /dev/null
+++ b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/TestException.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tests.sysmem.host;
+
+/**
+ * Exception thrown in case of unexpected error encountered when executing the
+ * test.
+ */
+class TestException extends Exception {
+    TestException(Exception cause) {
+        super(cause);
+    }
+
+    TestException(String msg) {
+        super(msg);
+    }
+
+    TestException(String msg, Exception cause) {
+        super(msg, cause);
+    }
+}
diff --git a/tests/net/AndroidManifest.xml b/tests/net/AndroidManifest.xml
index ba1a2ea..6dae3f1 100644
--- a/tests/net/AndroidManifest.xml
+++ b/tests/net/AndroidManifest.xml
@@ -44,6 +44,7 @@
     <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
     <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
     <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
+    <uses-permission android:name="android.permission.NETWORK_STACK" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java b/tests/net/java/android/net/ip/IpServerTest.java
similarity index 71%
rename from tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
rename to tests/net/java/android/net/ip/IpServerTest.java
index 5934653..cff0b54 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
+++ b/tests/net/java/android/net/ip/IpServerTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.connectivity.tethering;
+package android.net.ip;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -37,9 +37,9 @@
 import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
 import static android.net.ConnectivityManager.TETHERING_USB;
 import static android.net.ConnectivityManager.TETHERING_WIFI;
-import static com.android.server.connectivity.tethering.IControlsTethering.STATE_AVAILABLE;
-import static com.android.server.connectivity.tethering.IControlsTethering.STATE_TETHERED;
-import static com.android.server.connectivity.tethering.IControlsTethering.STATE_UNAVAILABLE;
+import static android.net.ip.IpServer.STATE_AVAILABLE;
+import static android.net.ip.IpServer.STATE_TETHERED;
+import static android.net.ip.IpServer.STATE_UNAVAILABLE;
 
 import android.net.INetworkStatsService;
 import android.net.InterfaceConfiguration;
@@ -50,7 +50,6 @@
 import android.net.RouteInfo;
 import android.net.dhcp.DhcpServer;
 import android.net.dhcp.DhcpServingParams;
-import android.net.ip.RouterAdvertisementDaemon;
 import android.net.util.InterfaceParams;
 import android.net.util.InterfaceSet;
 import android.net.util.SharedLog;
@@ -74,7 +73,7 @@
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
-public class TetherInterfaceStateMachineTest {
+public class IpServerTest {
     private static final String IFACE_NAME = "testnet1";
     private static final String UPSTREAM_IFACE = "upstream0";
     private static final String UPSTREAM_IFACE2 = "upstream1";
@@ -85,39 +84,38 @@
 
     @Mock private INetworkManagementService mNMService;
     @Mock private INetworkStatsService mStatsService;
-    @Mock private IControlsTethering mTetherHelper;
+    @Mock private IpServer.Callback mCallback;
     @Mock private InterfaceConfiguration mInterfaceConfiguration;
     @Mock private SharedLog mSharedLog;
     @Mock private DhcpServer mDhcpServer;
     @Mock private RouterAdvertisementDaemon mRaDaemon;
-    @Mock private TetheringDependencies mTetheringDependencies;
+    @Mock private IpServer.Dependencies mDependencies;
 
     @Captor private ArgumentCaptor<DhcpServingParams> mDhcpParamsCaptor;
 
     private final TestLooper mLooper = new TestLooper();
     private final ArgumentCaptor<LinkProperties> mLinkPropertiesCaptor =
             ArgumentCaptor.forClass(LinkProperties.class);
-    private TetherInterfaceStateMachine mTestedSm;
+    private IpServer mIpServer;
 
     private void initStateMachine(int interfaceType) throws Exception {
         initStateMachine(interfaceType, false /* usingLegacyDhcp */);
     }
 
     private void initStateMachine(int interfaceType, boolean usingLegacyDhcp) throws Exception {
-        mTestedSm = new TetherInterfaceStateMachine(
+        mIpServer = new IpServer(
                 IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog,
-                mNMService, mStatsService, mTetherHelper, usingLegacyDhcp,
-                mTetheringDependencies);
-        mTestedSm.start();
+                mNMService, mStatsService, mCallback, usingLegacyDhcp, mDependencies);
+        mIpServer.start();
         // Starting the state machine always puts us in a consistent state and notifies
         // the rest of the world that we've changed from an unknown to available state.
         mLooper.dispatchAll();
-        reset(mNMService, mStatsService, mTetherHelper);
+        reset(mNMService, mStatsService, mCallback);
         when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration);
-        when(mTetheringDependencies.makeDhcpServer(
+        when(mDependencies.makeDhcpServer(
                 any(), any(), mDhcpParamsCaptor.capture(), any())).thenReturn(mDhcpServer);
-        when(mTetheringDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon);
-        when(mTetheringDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS);
+        when(mDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon);
+        when(mDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS);
 
         when(mRaDaemon.start()).thenReturn(true);
     }
@@ -130,11 +128,11 @@
     private void initTetheredStateMachine(int interfaceType, String upstreamIface,
             boolean usingLegacyDhcp) throws Exception {
         initStateMachine(interfaceType, usingLegacyDhcp);
-        dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED);
+        dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
         if (upstreamIface != null) {
             dispatchTetherConnectionChanged(upstreamIface);
         }
-        reset(mNMService, mStatsService, mTetherHelper);
+        reset(mNMService, mStatsService, mCallback);
         when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration);
     }
 
@@ -145,34 +143,34 @@
 
     @Test
     public void startsOutAvailable() {
-        mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(),
-                TETHERING_BLUETOOTH, mSharedLog, mNMService, mStatsService, mTetherHelper,
-                false /* usingLegacyDhcp */, mTetheringDependencies);
-        mTestedSm.start();
+        mIpServer = new IpServer(IFACE_NAME, mLooper.getLooper(),
+                TETHERING_BLUETOOTH, mSharedLog, mNMService, mStatsService, mCallback,
+                false /* usingLegacyDhcp */, mDependencies);
+        mIpServer.start();
         mLooper.dispatchAll();
-        verify(mTetherHelper).updateInterfaceState(
-                mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
-        verify(mTetherHelper).updateLinkProperties(eq(mTestedSm), any(LinkProperties.class));
-        verifyNoMoreInteractions(mTetherHelper, mNMService, mStatsService);
+        verify(mCallback).updateInterfaceState(
+                mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
+        verify(mCallback).updateLinkProperties(eq(mIpServer), any(LinkProperties.class));
+        verifyNoMoreInteractions(mCallback, mNMService, mStatsService);
     }
 
     @Test
     public void shouldDoNothingUntilRequested() throws Exception {
         initStateMachine(TETHERING_BLUETOOTH);
         final int [] NOOP_COMMANDS = {
-            TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED,
-            TetherInterfaceStateMachine.CMD_IP_FORWARDING_ENABLE_ERROR,
-            TetherInterfaceStateMachine.CMD_IP_FORWARDING_DISABLE_ERROR,
-            TetherInterfaceStateMachine.CMD_START_TETHERING_ERROR,
-            TetherInterfaceStateMachine.CMD_STOP_TETHERING_ERROR,
-            TetherInterfaceStateMachine.CMD_SET_DNS_FORWARDERS_ERROR,
-            TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED
+            IpServer.CMD_TETHER_UNREQUESTED,
+            IpServer.CMD_IP_FORWARDING_ENABLE_ERROR,
+            IpServer.CMD_IP_FORWARDING_DISABLE_ERROR,
+            IpServer.CMD_START_TETHERING_ERROR,
+            IpServer.CMD_STOP_TETHERING_ERROR,
+            IpServer.CMD_SET_DNS_FORWARDERS_ERROR,
+            IpServer.CMD_TETHER_CONNECTION_CHANGED
         };
         for (int command : NOOP_COMMANDS) {
             // None of these commands should trigger us to request action from
             // the rest of the system.
             dispatchCommand(command);
-            verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+            verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
         }
     }
 
@@ -180,57 +178,57 @@
     public void handlesImmediateInterfaceDown() throws Exception {
         initStateMachine(TETHERING_BLUETOOTH);
 
-        dispatchCommand(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
-        verify(mTetherHelper).updateInterfaceState(
-                mTestedSm, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
-        verify(mTetherHelper).updateLinkProperties(eq(mTestedSm), any(LinkProperties.class));
-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+        dispatchCommand(IpServer.CMD_INTERFACE_DOWN);
+        verify(mCallback).updateInterfaceState(
+                mIpServer, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
+        verify(mCallback).updateLinkProperties(eq(mIpServer), any(LinkProperties.class));
+        verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
     }
 
     @Test
     public void canBeTethered() throws Exception {
         initStateMachine(TETHERING_BLUETOOTH);
 
-        dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED);
-        InOrder inOrder = inOrder(mTetherHelper, mNMService);
+        dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
+        InOrder inOrder = inOrder(mCallback, mNMService);
         inOrder.verify(mNMService).tetherInterface(IFACE_NAME);
-        inOrder.verify(mTetherHelper).updateInterfaceState(
-                mTestedSm, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
-        inOrder.verify(mTetherHelper).updateLinkProperties(
-                eq(mTestedSm), any(LinkProperties.class));
-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+        inOrder.verify(mCallback).updateInterfaceState(
+                mIpServer, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
+        inOrder.verify(mCallback).updateLinkProperties(
+                eq(mIpServer), any(LinkProperties.class));
+        verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
     }
 
     @Test
     public void canUnrequestTethering() throws Exception {
         initTetheredStateMachine(TETHERING_BLUETOOTH, null);
 
-        dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
-        InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper);
+        dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED);
+        InOrder inOrder = inOrder(mNMService, mStatsService, mCallback);
         inOrder.verify(mNMService).untetherInterface(IFACE_NAME);
         inOrder.verify(mNMService).setInterfaceConfig(eq(IFACE_NAME), any());
-        inOrder.verify(mTetherHelper).updateInterfaceState(
-                mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
-        inOrder.verify(mTetherHelper).updateLinkProperties(
-                eq(mTestedSm), any(LinkProperties.class));
-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+        inOrder.verify(mCallback).updateInterfaceState(
+                mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
+        inOrder.verify(mCallback).updateLinkProperties(
+                eq(mIpServer), any(LinkProperties.class));
+        verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
     }
 
     @Test
     public void canBeTetheredAsUsb() throws Exception {
         initStateMachine(TETHERING_USB);
 
-        dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED);
-        InOrder inOrder = inOrder(mTetherHelper, mNMService);
+        dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
+        InOrder inOrder = inOrder(mCallback, mNMService);
         inOrder.verify(mNMService).getInterfaceConfig(IFACE_NAME);
         inOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration);
         inOrder.verify(mNMService).tetherInterface(IFACE_NAME);
-        inOrder.verify(mTetherHelper).updateInterfaceState(
-                mTestedSm, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
-        inOrder.verify(mTetherHelper).updateLinkProperties(
-                eq(mTestedSm), mLinkPropertiesCaptor.capture());
+        inOrder.verify(mCallback).updateInterfaceState(
+                mIpServer, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
+        inOrder.verify(mCallback).updateLinkProperties(
+                eq(mIpServer), mLinkPropertiesCaptor.capture());
         assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue());
-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+        verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
     }
 
     @Test
@@ -243,7 +241,7 @@
         InOrder inOrder = inOrder(mNMService);
         inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE);
         inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+        verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
     }
 
     @Test
@@ -257,7 +255,7 @@
         inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
         inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
         inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+        verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
     }
 
     @Test
@@ -300,18 +298,18 @@
     public void canUnrequestTetheringWithUpstream() throws Exception {
         initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE);
 
-        dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
-        InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper);
+        dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED);
+        InOrder inOrder = inOrder(mNMService, mStatsService, mCallback);
         inOrder.verify(mStatsService).forceUpdate();
         inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
         inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
         inOrder.verify(mNMService).untetherInterface(IFACE_NAME);
         inOrder.verify(mNMService).setInterfaceConfig(eq(IFACE_NAME), any());
-        inOrder.verify(mTetherHelper).updateInterfaceState(
-                mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
-        inOrder.verify(mTetherHelper).updateLinkProperties(
-                eq(mTestedSm), any(LinkProperties.class));
-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+        inOrder.verify(mCallback).updateInterfaceState(
+                mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
+        inOrder.verify(mCallback).updateLinkProperties(
+                eq(mIpServer), any(LinkProperties.class));
+        verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
     }
 
     @Test
@@ -322,15 +320,15 @@
             if (shouldThrow) {
                 doThrow(RemoteException.class).when(mNMService).untetherInterface(IFACE_NAME);
             }
-            dispatchCommand(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
-            InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper);
+            dispatchCommand(IpServer.CMD_INTERFACE_DOWN);
+            InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mCallback);
             usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
             usbTeardownOrder.verify(mNMService).setInterfaceConfig(
                     IFACE_NAME, mInterfaceConfiguration);
-            usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
-                    mTestedSm, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
-            usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
-                    eq(mTestedSm), mLinkPropertiesCaptor.capture());
+            usbTeardownOrder.verify(mCallback).updateInterfaceState(
+                    mIpServer, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
+            usbTeardownOrder.verify(mCallback).updateLinkProperties(
+                    eq(mIpServer), mLinkPropertiesCaptor.capture());
             assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
         }
     }
@@ -340,15 +338,15 @@
         initStateMachine(TETHERING_USB);
 
         doThrow(RemoteException.class).when(mNMService).tetherInterface(IFACE_NAME);
-        dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED);
-        InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper);
+        dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
+        InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mCallback);
         usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
         usbTeardownOrder.verify(mNMService).setInterfaceConfig(
                 IFACE_NAME, mInterfaceConfiguration);
-        usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
-                mTestedSm, STATE_AVAILABLE, TETHER_ERROR_TETHER_IFACE_ERROR);
-        usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
-                eq(mTestedSm), mLinkPropertiesCaptor.capture());
+        usbTeardownOrder.verify(mCallback).updateInterfaceState(
+                mIpServer, STATE_AVAILABLE, TETHER_ERROR_TETHER_IFACE_ERROR);
+        usbTeardownOrder.verify(mCallback).updateLinkProperties(
+                eq(mIpServer), mLinkPropertiesCaptor.capture());
         assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
     }
 
@@ -358,13 +356,13 @@
 
         doThrow(RemoteException.class).when(mNMService).enableNat(anyString(), anyString());
         dispatchTetherConnectionChanged(UPSTREAM_IFACE);
-        InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper);
+        InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mCallback);
         usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
         usbTeardownOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration);
-        usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
-                mTestedSm, STATE_AVAILABLE, TETHER_ERROR_ENABLE_NAT_ERROR);
-        usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
-                eq(mTestedSm), mLinkPropertiesCaptor.capture());
+        usbTeardownOrder.verify(mCallback).updateInterfaceState(
+                mIpServer, STATE_AVAILABLE, TETHER_ERROR_ENABLE_NAT_ERROR);
+        usbTeardownOrder.verify(mCallback).updateLinkProperties(
+                eq(mIpServer), mLinkPropertiesCaptor.capture());
         assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
     }
 
@@ -372,11 +370,11 @@
     public void ignoresDuplicateUpstreamNotifications() throws Exception {
         initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
 
-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+        verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
 
         for (int i = 0; i < 5; i++) {
             dispatchTetherConnectionChanged(UPSTREAM_IFACE);
-            verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+            verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
         }
     }
 
@@ -401,11 +399,11 @@
         initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, true /* usingLegacyDhcp */);
         dispatchTetherConnectionChanged(UPSTREAM_IFACE);
 
-        verify(mTetheringDependencies, never()).makeDhcpServer(any(), any(), any(), any());
+        verify(mDependencies, never()).makeDhcpServer(any(), any(), any(), any());
     }
 
     private void assertDhcpStarted(IpPrefix expectedPrefix) {
-        verify(mTetheringDependencies, times(1)).makeDhcpServer(
+        verify(mDependencies, times(1)).makeDhcpServer(
                 eq(mLooper.getLooper()), eq(TEST_IFACE_PARAMS), any(), eq(mSharedLog));
         verify(mDhcpServer, times(1)).start();
         final DhcpServingParams params = mDhcpParamsCaptor.getValue();
@@ -422,21 +420,21 @@
     /**
      * Send a command to the state machine under test, and run the event loop to idle.
      *
-     * @param command One of the TetherInterfaceStateMachine.CMD_* constants.
+     * @param command One of the IpServer.CMD_* constants.
      * @param arg1 An additional argument to pass.
      */
     private void dispatchCommand(int command, int arg1) {
-        mTestedSm.sendMessage(command, arg1);
+        mIpServer.sendMessage(command, arg1);
         mLooper.dispatchAll();
     }
 
     /**
      * Send a command to the state machine under test, and run the event loop to idle.
      *
-     * @param command One of the TetherInterfaceStateMachine.CMD_* constants.
+     * @param command One of the IpServer.CMD_* constants.
      */
     private void dispatchCommand(int command) {
-        mTestedSm.sendMessage(command);
+        mIpServer.sendMessage(command);
         mLooper.dispatchAll();
     }
 
@@ -447,7 +445,7 @@
      * @param upstreamIface String name of upstream interface (or null)
      */
     private void dispatchTetherConnectionChanged(String upstreamIface) {
-        mTestedSm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
+        mIpServer.sendMessage(IpServer.CMD_TETHER_CONNECTION_CHANGED,
                 new InterfaceSet(upstreamIface));
         mLooper.dispatchAll();
     }
diff --git a/tests/net/java/android/net/netlink/InetDiagSocketTest.java b/tests/net/java/android/net/netlink/InetDiagSocketTest.java
new file mode 100644
index 0000000..39ecb7e5a
--- /dev/null
+++ b/tests/net/java/android/net/netlink/InetDiagSocketTest.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.netlink;
+
+import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
+import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
+import static android.os.Process.INVALID_UID;
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.IPPROTO_TCP;
+import static android.system.OsConstants.IPPROTO_UDP;
+import static android.system.OsConstants.SOCK_DGRAM;
+import static android.system.OsConstants.SOCK_STREAM;
+import static android.system.OsConstants.SOL_SOCKET;
+import static android.system.OsConstants.SO_RCVTIMEO;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.netlink.StructNlMsgHdr;
+import android.os.Process;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.filters.SmallTest;
+import android.support.test.InstrumentationRegistry;
+import android.system.Os;
+import android.system.StructTimeval;
+import android.util.Log;
+import java.io.FileDescriptor;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import libcore.util.HexEncoding;
+
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class InetDiagSocketTest {
+    private final String TAG = "InetDiagSocketTest";
+    private ConnectivityManager mCm;
+    private Context mContext;
+    private final static int SOCKET_TIMEOUT_MS = 100;
+    private boolean mInetDiagUdpEnabled;
+
+    @Before
+    public void setUp() throws Exception {
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        mContext = instrumentation.getTargetContext();
+        mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+        int expectedUid = Process.myUid();
+        UdpConnection udp = new UdpConnection("127.0.0.1", "127.0.0.2");
+        int uid = mCm.getConnectionOwnerUid(udp.protocol, udp.local, udp.remote);
+        mInetDiagUdpEnabled = (uid == expectedUid);
+    }
+
+    private class Connection {
+        public int socketDomain;
+        public int socketType;
+        public InetAddress localAddress;
+        public InetAddress remoteAddress;
+        public InetAddress localhostAddress;
+        public InetSocketAddress local;
+        public InetSocketAddress remote;
+        public int protocol;
+        public FileDescriptor localFd;
+        public FileDescriptor remoteFd;
+
+        public FileDescriptor createSocket() throws Exception {
+            return Os.socket(socketDomain, socketType, protocol);
+        }
+
+        public Connection(String to, String from) throws Exception {
+            remoteAddress = InetAddress.getByName(to);
+            if (from != null) {
+                localAddress = InetAddress.getByName(from);
+            } else {
+                localAddress = (remoteAddress instanceof Inet4Address) ?
+                        Inet4Address.getByName("localhost") : Inet6Address.getByName("::");
+            }
+            if ((localAddress instanceof Inet4Address) && (remoteAddress instanceof Inet4Address)) {
+                socketDomain = AF_INET;
+                localhostAddress = Inet4Address.getByName("localhost");
+            } else {
+                socketDomain = AF_INET6;
+                localhostAddress = Inet6Address.getByName("::");
+            }
+        }
+
+        public void close() throws Exception {
+            Os.close(localFd);
+        }
+    }
+
+    private class TcpConnection extends Connection {
+        public TcpConnection(String to, String from) throws Exception {
+            super(to, from);
+            protocol = IPPROTO_TCP;
+            socketType = SOCK_STREAM;
+
+            remoteFd = createSocket();
+            Os.bind(remoteFd, remoteAddress, 0);
+            Os.listen(remoteFd, 10);
+            int remotePort = ((InetSocketAddress) Os.getsockname(remoteFd)).getPort();
+
+            localFd = createSocket();
+            Os.bind(localFd, localAddress, 0);
+            Os.connect(localFd, remoteAddress, remotePort);
+
+            local = (InetSocketAddress) Os.getsockname(localFd);
+            remote = (InetSocketAddress) Os.getpeername(localFd);
+        }
+
+        public void close() throws Exception {
+            super.close();
+            Os.close(remoteFd);
+        }
+    }
+    private class UdpConnection extends Connection {
+        public UdpConnection(String to, String from) throws Exception {
+            super(to, from);
+            protocol = IPPROTO_UDP;
+            socketType = SOCK_DGRAM;
+
+            remoteFd = null;
+            localFd = createSocket();
+            Os.bind(localFd, localAddress, 0);
+
+            Os.connect(localFd, remoteAddress, 7);
+            local = (InetSocketAddress) Os.getsockname(localFd);
+            remote = new InetSocketAddress(remoteAddress, 7);
+        }
+    }
+
+    private void checkConnectionOwnerUid(int protocol, InetSocketAddress local,
+                                         InetSocketAddress remote, boolean expectSuccess) {
+        final int expectedUid = expectSuccess ? Process.myUid() : INVALID_UID;
+        final int uid = mCm.getConnectionOwnerUid(protocol, local, remote);
+        assertEquals(expectedUid, uid);
+    }
+
+    private int findLikelyFreeUdpPort(UdpConnection conn) throws Exception {
+        UdpConnection udp = new UdpConnection(conn.remoteAddress.getHostAddress(),
+                conn.localAddress.getHostAddress());
+        final int localPort = udp.local.getPort();
+        udp.close();
+        return localPort;
+    }
+
+    public void checkGetConnectionOwnerUid(String to, String from) throws Exception {
+        /**
+         * For TCP connections, create a test connection and verify that this
+         * {protocol, local, remote} socket result in receiving a valid UID.
+         */
+        TcpConnection tcp = new TcpConnection(to, from);
+        checkConnectionOwnerUid(tcp.protocol, tcp.local, tcp.remote, true);
+        checkConnectionOwnerUid(IPPROTO_UDP, tcp.local, tcp.remote, false);
+        checkConnectionOwnerUid(tcp.protocol, new InetSocketAddress(0), tcp.remote, false);
+        checkConnectionOwnerUid(tcp.protocol, tcp.local, new InetSocketAddress(0), false);
+        tcp.close();
+
+        /**
+         * TODO: STOPSHIP: Always test for UDP, do not allow opt-out.
+         */
+        if (!mInetDiagUdpEnabled) return;
+
+        /**
+         * For UDP connections, either a complete match {protocol, local, remote} or a
+         * partial match {protocol, local} should return a valid UID.
+         */
+        UdpConnection udp = new UdpConnection(to,from);
+        checkConnectionOwnerUid(udp.protocol, udp.local, udp.remote, true);
+        checkConnectionOwnerUid(udp.protocol, udp.local, new InetSocketAddress(0), true);
+        checkConnectionOwnerUid(IPPROTO_TCP, udp.local, udp.remote, false);
+        checkConnectionOwnerUid(udp.protocol, new InetSocketAddress(findLikelyFreeUdpPort(udp)),
+                udp.remote, false);
+        udp.close();
+    }
+
+    @Test
+    public void testGetConnectionOwnerUid() throws Exception {
+        checkGetConnectionOwnerUid("::", null);
+        checkGetConnectionOwnerUid("::", "::");
+        checkGetConnectionOwnerUid("0.0.0.0", null);
+        checkGetConnectionOwnerUid("0.0.0.0", "0.0.0.0");
+        checkGetConnectionOwnerUid("127.0.0.1", null);
+        checkGetConnectionOwnerUid("127.0.0.1", "127.0.0.2");
+        checkGetConnectionOwnerUid("::1", null);
+        checkGetConnectionOwnerUid("::1", "::1");
+    }
+
+    // Hexadecimal representation of InetDiagReqV2 request.
+    private static final String INET_DIAG_REQ_V2_UDP_INET4_HEX =
+            // struct nlmsghdr
+            "48000000" +     // length = 72
+            "1400" +         // type = SOCK_DIAG_BY_FAMILY
+            "0103" +         // flags = NLM_F_REQUEST | NLM_F_DUMP
+            "00000000" +     // seqno
+            "00000000" +     // pid (0 == kernel)
+            // struct inet_diag_req_v2
+            "02" +           // family = AF_INET
+            "11" +           // protcol = IPPROTO_UDP
+            "00" +           // idiag_ext
+            "00" +           // pad
+            "ffffffff" +     // idiag_states
+            // inet_diag_sockid
+            "a5de" +         // idiag_sport = 42462
+            "b971" +         // idiag_dport = 47473
+            "0a006402000000000000000000000000" + // idiag_src = 10.0.100.2
+            "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8
+            "00000000" +     // idiag_if
+            "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE
+    private static final byte[] INET_DIAG_REQ_V2_UDP_INET4_BYTES =
+            HexEncoding.decode(INET_DIAG_REQ_V2_UDP_INET4_HEX.toCharArray(), false);
+
+    @Test
+    public void testInetDiagReqV2UdpInet4() throws Exception {
+        InetSocketAddress local = new InetSocketAddress(InetAddress.getByName("10.0.100.2"),
+                42462);
+        InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"),
+                47473);
+        final byte[] msg = InetDiagMessage.InetDiagReqV2(IPPROTO_UDP, local, remote, AF_INET,
+                (short) (NLM_F_REQUEST | NLM_F_DUMP));
+        assertArrayEquals(INET_DIAG_REQ_V2_UDP_INET4_BYTES, msg);
+    }
+
+    // Hexadecimal representation of InetDiagReqV2 request.
+    private static final String INET_DIAG_REQ_V2_TCP_INET6_HEX =
+            // struct nlmsghdr
+            "48000000" +     // length = 72
+            "1400" +         // type = SOCK_DIAG_BY_FAMILY
+            "0100" +         // flags = NLM_F_REQUEST
+            "00000000" +     // seqno
+            "00000000" +     // pid (0 == kernel)
+            // struct inet_diag_req_v2
+            "0a" +           // family = AF_INET6
+            "06" +           // protcol = IPPROTO_TCP
+            "00" +           // idiag_ext
+            "00" +           // pad
+            "ffffffff" +     // idiag_states
+                // inet_diag_sockid
+                "a5de" +         // idiag_sport = 42462
+                "b971" +         // idiag_dport = 47473
+                "fe8000000000000086c9b2fffe6aed4b" + // idiag_src = fe80::86c9:b2ff:fe6a:ed4b
+                "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8
+                "00000000" +     // idiag_if
+                "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE
+    private static final byte[] INET_DIAG_REQ_V2_TCP_INET6_BYTES =
+            HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET6_HEX.toCharArray(), false);
+
+    @Test
+    public void testInetDiagReqV2TcpInet6() throws Exception {
+        InetSocketAddress local = new InetSocketAddress(
+                InetAddress.getByName("fe80::86c9:b2ff:fe6a:ed4b"), 42462);
+        InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"),
+                47473);
+        byte[] msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, remote, AF_INET6,
+                NLM_F_REQUEST);
+
+        assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_BYTES, msg);
+    }
+
+    // Hexadecimal representation of InetDiagReqV2 request.
+    private static final String INET_DIAG_MSG_HEX =
+            // struct nlmsghdr
+            "58000000" +     // length = 88
+            "1400" +         // type = SOCK_DIAG_BY_FAMILY
+            "0200" +         // flags = NLM_F_MULTI
+            "00000000" +     // seqno
+            "f5220000" +     // pid (0 == kernel)
+            // struct inet_diag_msg
+            "0a" +           // family = AF_INET6
+            "01" +           // idiag_state
+            "00" +           // idiag_timer
+            "00" +           // idiag_retrans
+                // inet_diag_sockid
+                "a817" +     // idiag_sport = 43031
+                "960f" +     // idiag_dport = 38415
+                "fe8000000000000086c9b2fffe6aed4b" + // idiag_src = fe80::86c9:b2ff:fe6a:ed4b
+                "00000000000000000000ffff08080808" + // idiag_dst = 8.8.8.8
+                "00000000" + // idiag_if
+                "ffffffffffffffff" + // idiag_cookie = INET_DIAG_NOCOOKIE
+            "00000000" +     // idiag_expires
+            "00000000" +     // idiag_rqueue
+            "00000000" +     // idiag_wqueue
+            "a3270000" +     // idiag_uid
+            "A57E1900";      // idiag_inode
+    private static final byte[] INET_DIAG_MSG_BYTES =
+            HexEncoding.decode(INET_DIAG_MSG_HEX.toCharArray(), false);
+
+    @Test
+    public void testParseInetDiagResponse() throws Exception {
+        final ByteBuffer byteBuffer = ByteBuffer.wrap(INET_DIAG_MSG_BYTES);
+        byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
+        final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
+        assertNotNull(msg);
+
+        assertTrue(msg instanceof InetDiagMessage);
+        final InetDiagMessage inetDiagMsg = (InetDiagMessage) msg;
+        assertEquals(10147, inetDiagMsg.mStructInetDiagMsg.idiag_uid);
+
+        final StructNlMsgHdr hdr = inetDiagMsg.getHeader();
+        assertNotNull(hdr);
+        assertEquals(NetlinkConstants.SOCK_DIAG_BY_FAMILY, hdr.nlmsg_type);
+        assertEquals(StructNlMsgHdr.NLM_F_MULTI, hdr.nlmsg_flags);
+        assertEquals(0, hdr.nlmsg_seq);
+        assertEquals(8949, hdr.nlmsg_pid);
+    }
+}
diff --git a/tests/net/java/android/net/util/SharedLogTest.java b/tests/net/java/android/net/util/SharedLogTest.java
index d46facf..8604860 100644
--- a/tests/net/java/android/net/util/SharedLogTest.java
+++ b/tests/net/java/android/net/util/SharedLogTest.java
@@ -44,6 +44,8 @@
         final SharedLog logLevel2a = logTop.forSubComponent("twoA");
         final SharedLog logLevel2b = logTop.forSubComponent("twoB");
         logLevel2b.e("2b or not 2b");
+        logLevel2b.e("No exception", null);
+        logLevel2b.e("Wait, here's one", new Exception("Test"));
         logLevel2a.w("second post?");
 
         final SharedLog logLevel3 = logLevel2a.forSubComponent("three");
@@ -54,6 +56,9 @@
         final String[] expected = {
             " - MARK first post!",
             " - [twoB] ERROR 2b or not 2b",
+            " - [twoB] ERROR No exception",
+            // No stacktrace in shared log, only in logcat
+            " - [twoB] ERROR Wait, here's one: Test",
             " - [twoA] WARN second post?",
             " - still logging",
             " - [twoA.three] 3 >> 2",
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index 0d3b8e4..40d5544 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -75,6 +75,7 @@
 import android.net.NetworkState;
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
+import android.net.ip.IpServer;
 import android.net.ip.RouterAdvertisementDaemon;
 import android.net.util.InterfaceParams;
 import android.net.util.NetworkConstants;
@@ -99,10 +100,8 @@
 import com.android.internal.util.StateMachine;
 import com.android.internal.util.test.BroadcastInterceptingContext;
 import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.server.connectivity.tethering.IControlsTethering;
 import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
 import com.android.server.connectivity.tethering.OffloadHardwareInterface;
-import com.android.server.connectivity.tethering.TetherInterfaceStateMachine;
 import com.android.server.connectivity.tethering.TetheringDependencies;
 import com.android.server.connectivity.tethering.UpstreamNetworkMonitor;
 
@@ -190,7 +189,7 @@
 
     public class MockTetheringDependencies extends TetheringDependencies {
         StateMachine upstreamNetworkMonitorMasterSM;
-        ArrayList<TetherInterfaceStateMachine> ipv6CoordinatorNotifyList;
+        ArrayList<IpServer> ipv6CoordinatorNotifyList;
         int isTetheringSupportedCalls;
 
         public void reset() {
@@ -213,29 +212,35 @@
 
         @Override
         public IPv6TetheringCoordinator getIPv6TetheringCoordinator(
-                ArrayList<TetherInterfaceStateMachine> notifyList, SharedLog log) {
+                ArrayList<IpServer> notifyList, SharedLog log) {
             ipv6CoordinatorNotifyList = notifyList;
             return mIPv6TetheringCoordinator;
         }
 
         @Override
-        public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) {
-            return mRouterAdvertisementDaemon;
-        }
+        public IpServer.Dependencies getIpServerDependencies() {
+            return new IpServer.Dependencies() {
+                @Override
+                public RouterAdvertisementDaemon getRouterAdvertisementDaemon(
+                        InterfaceParams ifParams) {
+                    return mRouterAdvertisementDaemon;
+                }
 
-        @Override
-        public INetd getNetdService() {
-            return mNetd;
-        }
+                @Override
+                public InterfaceParams getInterfaceParams(String ifName) {
+                    final String[] ifaces = new String[] {
+                            TEST_USB_IFNAME, TEST_WLAN_IFNAME, TEST_MOBILE_IFNAME };
+                    final int index = ArrayUtils.indexOf(ifaces, ifName);
+                    assertTrue("Non-mocked interface: " + ifName, index >= 0);
+                    return new InterfaceParams(ifName, index + IFINDEX_OFFSET,
+                            MacAddress.ALL_ZEROS_ADDRESS);
+                }
 
-        @Override
-        public InterfaceParams getInterfaceParams(String ifName) {
-            final String[] ifaces = new String[] { TEST_USB_IFNAME, TEST_WLAN_IFNAME,
-                    TEST_MOBILE_IFNAME };
-            final int index = ArrayUtils.indexOf(ifaces, ifName);
-            assertTrue("Non-mocked interface: " + ifName, index >= 0);
-            return new InterfaceParams(ifName, index + IFINDEX_OFFSET,
-                    MacAddress.ALL_ZEROS_ADDRESS);
+                @Override
+                public INetd getNetdService() {
+                    return mNetd;
+                }
+            };
         }
 
         @Override
@@ -458,9 +463,9 @@
         sendWifiApStateChanged(WIFI_AP_STATE_ENABLED);
         mLooper.dispatchAll();
 
-        // If, and only if, Tethering received an interface status changed
-        // then it creates a TetherInterfaceStateMachine and sends out a
-        // broadcast indicating that the interface is "available".
+        // If, and only if, Tethering received an interface status changed then
+        // it creates a IpServer and sends out a broadcast indicating that the
+        // interface is "available".
         if (emulateInterfaceStatusChanged) {
             assertEquals(1, mTetheringDependencies.isTetheringSupportedCalls);
             verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
@@ -557,18 +562,18 @@
     }
 
     /**
-     * Send CMD_IPV6_TETHER_UPDATE to TISMs as would be done by IPv6TetheringCoordinator.
+     * Send CMD_IPV6_TETHER_UPDATE to IpServers as would be done by IPv6TetheringCoordinator.
      */
     private void sendIPv6TetherUpdates(NetworkState upstreamState) {
         // IPv6TetheringCoordinator must have been notified of downstream
         verify(mIPv6TetheringCoordinator, times(1)).addActiveDownstream(
                 argThat(sm -> sm.linkProperties().getInterfaceName().equals(TEST_USB_IFNAME)),
-                eq(IControlsTethering.STATE_TETHERED));
+                eq(IpServer.STATE_TETHERED));
 
-        for (TetherInterfaceStateMachine tism :
+        for (IpServer ipSrv :
                 mTetheringDependencies.ipv6CoordinatorNotifyList) {
             NetworkState ipv6OnlyState = buildMobileUpstreamState(false, true, false);
-            tism.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0,
+            ipSrv.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0,
                     upstreamState.linkProperties.isIPv6Provisioned()
                             ? ipv6OnlyState.linkProperties
                             : null);
@@ -812,7 +817,7 @@
 
         // We verify get/set called thrice here: once for setup and twice during
         // teardown because all events happen over the course of the single
-        // dispatchAll() above. Note that once the TISM IPv4 address config
+        // dispatchAll() above. Note that once the IpServer IPv4 address config
         // code is refactored the two calls during shutdown will revert to one.
         verify(mNMService, times(2)).getInterfaceConfig(TEST_WLAN_IFNAME);
         verify(mNMService, times(3))
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index 2ecf25b..c02ca21 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -83,6 +83,7 @@
         "compile/Pseudolocalizer.cpp",
         "compile/XmlIdCollector.cpp",
         "configuration/ConfigurationParser.cpp",
+        "dump/DumpManifest.cpp",
         "filter/AbiFilter.cpp",
         "filter/ConfigFilter.cpp",
         "format/Archive.cpp",
diff --git a/tools/aapt2/Diagnostics.h b/tools/aapt2/Diagnostics.h
index 50e8b33..30deb55 100644
--- a/tools/aapt2/Diagnostics.h
+++ b/tools/aapt2/Diagnostics.h
@@ -133,11 +133,19 @@
   void Log(Level level, DiagMessageActual& actual_msg) override {
     actual_msg.source.path = source_.path;
     diag_->Log(level, actual_msg);
+    if (level == Level::Error) {
+      error = true;
+    }
+  }
+
+  bool HadError() {
+    return error;
   }
 
  private:
   Source source_;
   IDiagnostics* diag_;
+  bool error = false;
 
   DISALLOW_COPY_AND_ASSIGN(SourcePathDiagnostics);
 };
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp
index a73d56c..a20b9b7 100644
--- a/tools/aapt2/LoadedApk.cpp
+++ b/tools/aapt2/LoadedApk.cpp
@@ -69,8 +69,8 @@
       return {};
     }
 
-    io::ZeroCopyInputAdaptor adaptor(in.get());
-    if (!pb_table.ParseFromZeroCopyStream(&adaptor)) {
+    io::ProtoInputStreamReader proto_reader(in.get());
+    if (!proto_reader.ReadMessage(&pb_table)) {
       diag->Error(DiagMessage(source) << "failed to read " << kProtoResourceTablePath);
       return {};
     }
@@ -97,8 +97,8 @@
   }
 
   pb::XmlNode pb_node;
-  io::ZeroCopyInputAdaptor manifest_adaptor(manifest_in.get());
-  if (!pb_node.ParseFromZeroCopyStream(&manifest_adaptor)) {
+  io::ProtoInputStreamReader proto_reader(manifest_in.get());
+  if (!proto_reader.ReadMessage(&pb_node)) {
     diag->Error(DiagMessage(source) << "failed to read proto " << kAndroidManifestPath);
     return {};
   }
@@ -255,7 +255,7 @@
 }
 
 std::unique_ptr<xml::XmlResource> LoadedApk::LoadXml(const std::string& file_path,
-                                                     IDiagnostics* diag) {
+                                                     IDiagnostics* diag) const {
   io::IFile* file = apk_->FindFile(file_path);
   if (file == nullptr) {
     diag->Error(DiagMessage() << "failed to find file");
@@ -270,9 +270,9 @@
       return nullptr;
     }
 
-    io::ZeroCopyInputAdaptor adaptor(in.get());
     pb::XmlNode pb_node;
-    if (!pb_node.ParseFromZeroCopyStream(&adaptor)) {
+    io::ProtoInputStreamReader proto_reader(in.get());
+    if (!proto_reader.ReadMessage(&pb_node)) {
       diag->Error(DiagMessage() << "failed to parse file as proto XML");
       return nullptr;
     }
@@ -317,8 +317,8 @@
     std::unique_ptr<io::InputStream> manifest_in = manifest_file->OpenInputStream();
     if (manifest_in != nullptr) {
       pb::XmlNode pb_node;
-      io::ZeroCopyInputAdaptor manifest_adaptor(manifest_in.get());
-      if (pb_node.ParseFromZeroCopyStream(&manifest_adaptor)) {
+      io::ProtoInputStreamReader proto_reader(manifest_in.get());
+      if (!proto_reader.ReadMessage(&pb_node)) {
         return ApkFormat::kProto;
       }
     }
diff --git a/tools/aapt2/LoadedApk.h b/tools/aapt2/LoadedApk.h
index dcb085a..84c57c1 100644
--- a/tools/aapt2/LoadedApk.h
+++ b/tools/aapt2/LoadedApk.h
@@ -111,7 +111,7 @@
                               IArchiveWriter* writer, xml::XmlResource* manifest = nullptr);
 
   /** Loads the file as an xml document. */
-  std::unique_ptr<xml::XmlResource> LoadXml(const std::string& file_path, IDiagnostics* diag);
+  std::unique_ptr<xml::XmlResource> LoadXml(const std::string& file_path, IDiagnostics* diag) const;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(LoadedApk);
diff --git a/tools/aapt2/StringPool_test.cpp b/tools/aapt2/StringPool_test.cpp
index 0778564..9a7238b 100644
--- a/tools/aapt2/StringPool_test.cpp
+++ b/tools/aapt2/StringPool_test.cpp
@@ -303,7 +303,7 @@
   }
 }
 
-TEST(StringPoolTest, FlattenModifiedUTF8) {
+TEST(StringPoolTest, ModifiedUTF8) {
   using namespace android;  // For NO_ERROR on Windows.
   StdErrDiagnostics diag;
   StringPool pool;
@@ -315,12 +315,24 @@
   StringPool::FlattenUtf8(&buffer, pool, &diag);
   std::unique_ptr<uint8_t[]> data = util::Copy(buffer);
 
-  // Check that the 4 byte utf-8 codepoint is encoded using 2 3 byte surrogate pairs
+  // Check that the codepoints are encoded using two three-byte surrogate pairs
   ResStringPool test;
   ASSERT_EQ(test.setTo(data.get(), buffer.size()), NO_ERROR);
-  EXPECT_THAT(util::GetString(test, 0), Eq("\xED\xA0\x81\xED\xB0\x80"));
-  EXPECT_THAT(util::GetString(test, 1), Eq("foo \xED\xA0\x81\xED\xB0\xB7 bar"));
-  EXPECT_THAT(util::GetString(test, 2), Eq("\xED\xA0\x81\xED\xB0\x80\xED\xA0\x81\xED\xB0\xB7"));
+  size_t len;
+  const char* str = test.string8At(0, &len);
+  ASSERT_THAT(str, NotNull());
+  EXPECT_THAT(std::string(str, len), Eq("\xED\xA0\x81\xED\xB0\x80"));
+  str = test.string8At(1, &len);
+  ASSERT_THAT(str, NotNull());
+  EXPECT_THAT(std::string(str, len), Eq("foo \xED\xA0\x81\xED\xB0\xB7 bar"));
+  str = test.string8At(2, &len);
+  ASSERT_THAT(str, NotNull());
+  EXPECT_THAT(std::string(str, len), Eq("\xED\xA0\x81\xED\xB0\x80\xED\xA0\x81\xED\xB0\xB7"));
+
+  // Check that retrieving the strings returns the original UTF-8 character bytes
+  EXPECT_THAT(util::GetString(test, 0), Eq("\xF0\x90\x90\x80"));
+  EXPECT_THAT(util::GetString(test, 1), Eq("foo \xF0\x90\x90\xB7 bar"));
+  EXPECT_THAT(util::GetString(test, 2), Eq("\xF0\x90\x90\x80\xF0\x90\x90\xB7"));
 }
 
 TEST(StringPoolTest, MaxEncodingLength) {
diff --git a/tools/aapt2/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp
index 86b1f4c..954f1ed 100644
--- a/tools/aapt2/cmd/Convert.cpp
+++ b/tools/aapt2/cmd/Convert.cpp
@@ -170,8 +170,8 @@
       }
 
       pb::XmlNode pb_node;
-      io::ZeroCopyInputAdaptor adaptor(in.get());
-      if (!pb_node.ParseFromZeroCopyStream(&adaptor)) {
+      io::ProtoInputStreamReader proto_reader(in.get());
+      if (!proto_reader.ReadMessage(&pb_node)) {
         context_->GetDiagnostics()->Error(DiagMessage(source_)
                                           << "failed to parse proto XML " << *file->path);
         return false;
diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp
index 5cb30b6..91e3977 100644
--- a/tools/aapt2/cmd/Dump.cpp
+++ b/tools/aapt2/cmd/Dump.cpp
@@ -223,6 +223,12 @@
     return 1;
   }
 
+  ResourceTable* table = loaded_apk->GetResourceTable();
+  if (!table) {
+    diag_->Error(DiagMessage() << "Failed to retrieve resource table.");
+    return 1;
+  }
+
   io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
   Printer printer(&fout);
 
@@ -233,7 +239,7 @@
 
   // Insert the configurations into a set in order to keep every configuarion seen
   std::set<ConfigDescription, decltype(compare)> configs(compare);
-  for (auto& package : loaded_apk->GetResourceTable()->packages) {
+  for (auto& package : table->packages) {
     for (auto& type : package->types) {
       for (auto& entry : type->entries) {
         for (auto& value : entry->values) {
@@ -267,10 +273,15 @@
       return 1;
     }
 
+    ResourceTable* table = loaded_apk->GetResourceTable();
+    if (!table) {
+      diag_->Error(DiagMessage() << "Failed to retrieve resource table.");
+      return 1;
+    }
+
     // Load the run-time xml string pool using the flattened data
     BigBuffer buffer(4096);
-    StringPool::FlattenUtf8(&buffer, loaded_apk->GetResourceTable()->string_pool,
-                            context.GetDiagnostics());
+    StringPool::FlattenUtf8(&buffer, table->string_pool, context.GetDiagnostics());
     auto data = buffer.to_string();
     android::ResStringPool pool(data.data(), data.size(), false);
     Debug::DumpResStringPool(&pool, &printer);
@@ -304,7 +315,13 @@
       printer.Println("Binary APK");
     }
 
-    Debug::PrintTable(*loaded_apk->GetResourceTable(), print_options, &printer);
+    ResourceTable* table = loaded_apk->GetResourceTable();
+    if (!table) {
+      diag_->Error(DiagMessage() << "Failed to retrieve resource table.");
+      return 1;
+    }
+
+    Debug::PrintTable(*table, print_options, &printer);
   }
 
   return 0;
diff --git a/tools/aapt2/cmd/Dump.h b/tools/aapt2/cmd/Dump.h
index 0724d62..9ec820d 100644
--- a/tools/aapt2/cmd/Dump.h
+++ b/tools/aapt2/cmd/Dump.h
@@ -19,6 +19,7 @@
 
 #include "Command.h"
 #include "Debug.h"
+#include "dump/DumpManifest.h"
 
 namespace aapt {
 
@@ -133,8 +134,10 @@
  public:
   explicit DumpCommand(IDiagnostics* diag) : Command("dump", "d"), diag_(diag) {
     AddOptionalSubcommand(util::make_unique<DumpAPCCommand>(diag_));
+    AddOptionalSubcommand(util::make_unique<DumpBadgingCommand>(diag_));
     AddOptionalSubcommand(util::make_unique<DumpConfigsCommand>(diag_));
     AddOptionalSubcommand(util::make_unique<DumpPackageNameCommand>(diag_));
+    AddOptionalSubcommand(util::make_unique<DumpPermissionsCommand>(diag_));
     AddOptionalSubcommand(util::make_unique<DumpStringsCommand>(diag_));
     AddOptionalSubcommand(util::make_unique<DumpTableCommand>(diag_));
     AddOptionalSubcommand(util::make_unique<DumpXmlStringsCommand>(diag_));
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 119f56a..13c1047 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -1842,9 +1842,15 @@
     } else {
       // Adjust the SplitConstraints so that their SDK version is stripped if it is less than or
       // equal to the minSdk.
+      const size_t origConstraintSize = options_.split_constraints.size();
       options_.split_constraints =
           AdjustSplitConstraintsForMinSdk(context_->GetMinSdkVersion(), options_.split_constraints);
 
+      if (origConstraintSize != options_.split_constraints.size()) {
+        context_->GetDiagnostics()->Warn(DiagMessage()
+                                         << "requested to split resources prior to min sdk of "
+                                         << context_->GetMinSdkVersion());
+      }
       TableSplitter table_splitter(options_.split_constraints, options_.table_splitter_options);
       if (!table_splitter.VerifySplitConstraints(context_)) {
         return 1;
diff --git a/tools/aapt2/cmd/Util.cpp b/tools/aapt2/cmd/Util.cpp
index c6c82b0..5862d31 100644
--- a/tools/aapt2/cmd/Util.cpp
+++ b/tools/aapt2/cmd/Util.cpp
@@ -73,6 +73,7 @@
   }
 
   *out_path = parts[0];
+  out_split->name = parts[1];
   for (const StringPiece& config_str : util::Tokenize(parts[1], ',')) {
     ConfigDescription config;
     if (!ConfigDescription::Parse(config_str, &config)) {
@@ -119,12 +120,15 @@
   for (const SplitConstraints& constraints : split_constraints) {
     SplitConstraints constraint;
     for (const ConfigDescription& config : constraints.configs) {
-      if (config.sdkVersion <= min_sdk) {
-        constraint.configs.insert(config.CopyWithoutSdkVersion());
-      } else {
-        constraint.configs.insert(config);
+      const ConfigDescription &configToInsert = (config.sdkVersion <= min_sdk)
+          ? config.CopyWithoutSdkVersion()
+          : config;
+      // only add the config if it actually selects something
+      if (configToInsert != ConfigDescription::DefaultConfig()) {
+        constraint.configs.insert(configToInsert);
       }
     }
+    constraint.name = constraints.name;
     adjusted_constraints.push_back(std::move(constraint));
   }
   return adjusted_constraints;
diff --git a/tools/aapt2/cmd/Util_test.cpp b/tools/aapt2/cmd/Util_test.cpp
index b9fb5b2..158ef29 100644
--- a/tools/aapt2/cmd/Util_test.cpp
+++ b/tools/aapt2/cmd/Util_test.cpp
@@ -22,6 +22,10 @@
 #include "test/Test.h"
 
 namespace aapt {
+#define EXPECT_CONFIG_EQ(constraints, config) \
+    EXPECT_EQ(constraints.configs.size(), 1); \
+    EXPECT_EQ(*constraints.configs.begin(), config); \
+    constraints.configs.clear();
 
 TEST(UtilTest, SplitNamesAreSanitized) {
     AppInfo app_info{"com.pkg"};
@@ -84,4 +88,287 @@
   EXPECT_EQ(compiled_version_code_major->value.data, 0x61);
 }
 
+
+TEST (UtilTest, ParseSplitParameter) {
+  IDiagnostics* diagnostics = test::ContextBuilder().Build().get()->GetDiagnostics();
+  std::string path;
+  SplitConstraints constraints;
+  ConfigDescription expected_configuration;
+
+  // ========== Test IMSI ==========
+  // mcc: 'mcc[0-9]{3}'
+  // mnc: 'mnc[0-9]{1,3}'
+  ASSERT_TRUE(ParseSplitParameter(":mcc310",
+                                  diagnostics, &path, &constraints));
+  expected_configuration = test::ConfigDescriptionBuilder()
+      .setMcc(0x0136)
+      .Build();
+  EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+  ASSERT_TRUE(ParseSplitParameter(":mcc310-mnc004",
+                                  diagnostics, &path, &constraints));
+  expected_configuration = test::ConfigDescriptionBuilder()
+      .setMcc(0x0136)
+      .setMnc(0x0004)
+      .Build();
+  EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+  ASSERT_TRUE(ParseSplitParameter(":mcc310-mnc000",
+                                  diagnostics, &path, &constraints));
+  expected_configuration = test::ConfigDescriptionBuilder()
+      .setMcc(0x0136)
+      .setMnc(0xFFFF)
+      .Build();
+  EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+  // ========== Test LOCALE ==========
+  // locale: '[a-z]{2,3}(-r[a-z]{2})?'
+  // locale: 'b+[a-z]{2,3}(+[a-z[0-9]]{2})?'
+  ASSERT_TRUE(ParseSplitParameter(":es",
+                                  diagnostics, &path, &constraints));
+  expected_configuration = test::ConfigDescriptionBuilder()
+      .setLanguage(0x6573)
+      .Build();
+  EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+  ASSERT_TRUE(ParseSplitParameter(":fr-rCA",
+                                  diagnostics, &path, &constraints));
+  expected_configuration = test::ConfigDescriptionBuilder()
+      .setLanguage(0x6672)
+      .setCountry(0x4341)
+      .Build();
+  EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+  ASSERT_TRUE(ParseSplitParameter(":b+es+419",
+                                  diagnostics, &path, &constraints));
+  expected_configuration = test::ConfigDescriptionBuilder()
+      .setLanguage(0x6573)
+      .setCountry(0xA424)
+      .Build();
+  EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+  // ========== Test SCREEN_TYPE ==========
+  // orientation: '(port|land|square)'
+  // touchscreen: '(notouch|stylus|finger)'
+  // density" '(anydpi|nodpi|ldpi|mdpi|tvdpi|hdpi|xhdpi|xxhdpi|xxxhdpi|[0-9]*dpi)'
+  ASSERT_TRUE(ParseSplitParameter(":square",
+                                  diagnostics, &path, &constraints));
+  expected_configuration = test::ConfigDescriptionBuilder()
+      .setOrientation(0x03)
+      .Build();
+  EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+  ASSERT_TRUE(ParseSplitParameter(":stylus",
+                                  diagnostics, &path, &constraints));
+  expected_configuration = test::ConfigDescriptionBuilder()
+      .setTouchscreen(0x02)
+      .Build();
+  EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+  ASSERT_TRUE(ParseSplitParameter(":xxxhdpi",
+                                  diagnostics, &path, &constraints));
+  expected_configuration = test::ConfigDescriptionBuilder()
+      .setDensity(0x0280)
+      .setSdkVersion(0x0004) // version [any density requires donut]
+      .Build();
+  EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+  ASSERT_TRUE(ParseSplitParameter(":land-xhdpi-finger",
+                                  diagnostics, &path, &constraints));
+  expected_configuration = test::ConfigDescriptionBuilder()
+      .setOrientation(0x02)
+      .setTouchscreen(0x03)
+      .setDensity(0x0140)
+      .setSdkVersion(0x0004) // version [any density requires donut]
+      .Build();
+  EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+  // ========== Test INPUT ==========
+  // keyboard: '(nokeys|qwerty|12key)'
+  // navigation: '(nonav|dpad|trackball|wheel)'
+  // inputFlags: '(keysexposed|keyshidden|keyssoft)'
+  // inputFlags: '(navexposed|navhidden)'
+  ASSERT_TRUE(ParseSplitParameter(":qwerty",
+                                  diagnostics, &path, &constraints));
+  expected_configuration = test::ConfigDescriptionBuilder()
+      .setKeyboard(0x02)
+      .Build();
+  EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+  ASSERT_TRUE(ParseSplitParameter(":dpad",
+                                  diagnostics, &path, &constraints));
+  expected_configuration = test::ConfigDescriptionBuilder()
+      .setNavigation(0x02)
+      .Build();
+  EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+  ASSERT_TRUE(ParseSplitParameter(":keyssoft-navhidden",
+                                  diagnostics, &path, &constraints));
+  expected_configuration = test::ConfigDescriptionBuilder()
+      .setInputFlags(0x0B)
+      .Build();
+  EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+  ASSERT_TRUE(ParseSplitParameter(":keyshidden-nokeys-navexposed-trackball",
+                                  diagnostics, &path, &constraints));
+  expected_configuration = test::ConfigDescriptionBuilder()
+      .setKeyboard(0x01)
+      .setNavigation(0x03)
+      .setInputFlags(0x06)
+      .Build();
+  EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+  // ========== Test SCREEN_SIZE ==========
+  // screenWidth/screenHeight: '[0-9]+x[0-9]+'
+  ASSERT_TRUE(ParseSplitParameter(":1920x1080",
+                                  diagnostics, &path, &constraints));
+  expected_configuration = test::ConfigDescriptionBuilder()
+      .setScreenWidth(0x0780)
+      .setScreenHeight(0x0438)
+      .Build();
+  EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+  // ========== Test VERSION ==========
+  // version 'v[0-9]+'
+
+  // ========== Test SCREEN_CONFIG ==========
+  // screenLayout [direction]: '(ldltr|ldrtl)'
+  // screenLayout [size]: '(small|normal|large|xlarge)'
+  // screenLayout [long]: '(long|notlong)'
+  // uiMode [type]: '(desk|car|television|appliance|watch|vrheadset)'
+  // uiMode [night]: '(night|notnight)'
+  // smallestScreenWidthDp: 'sw[0-9]dp'
+  ASSERT_TRUE(ParseSplitParameter(":ldrtl",
+                                  diagnostics, &path, &constraints));
+  expected_configuration = test::ConfigDescriptionBuilder()
+      .setScreenLayout(0x80)
+      .Build();
+  EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+  ASSERT_TRUE(ParseSplitParameter(":small",
+                                  diagnostics, &path, &constraints));
+  expected_configuration = test::ConfigDescriptionBuilder()
+      .setScreenLayout(0x01)
+      .setSdkVersion(0x0004) // screenLayout (size) requires donut
+      .Build();
+  EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+  ASSERT_TRUE(ParseSplitParameter(":notlong",
+                                  diagnostics, &path, &constraints));
+  expected_configuration = test::ConfigDescriptionBuilder()
+      .setScreenLayout(0x10)
+      .setSdkVersion(0x0004) // screenLayout (long) requires donut
+      .Build();
+  EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+  ASSERT_TRUE(ParseSplitParameter(":ldltr-normal-long",
+                                  diagnostics, &path, &constraints));
+  expected_configuration = test::ConfigDescriptionBuilder()
+      .setScreenLayout(0x62)
+      .setSdkVersion(0x0004) // screenLayout (size|long) requires donut
+      .Build();
+  EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+  ASSERT_TRUE(ParseSplitParameter(":car",
+                                  diagnostics, &path, &constraints));
+  expected_configuration = test::ConfigDescriptionBuilder()
+      .setUiMode(0x03)
+      .setSdkVersion(0x0008) // uiMode requires froyo
+      .Build();
+  EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+  ASSERT_TRUE(ParseSplitParameter(":vrheadset",
+                                  diagnostics, &path, &constraints));
+  expected_configuration = test::ConfigDescriptionBuilder()
+      .setUiMode(0x07)
+      .setSdkVersion(0x001A) // uiMode 'vrheadset' requires oreo
+      .Build();
+  EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+  ASSERT_TRUE(ParseSplitParameter(":television-night",
+                                  diagnostics, &path, &constraints));
+  expected_configuration = test::ConfigDescriptionBuilder()
+      .setUiMode(0x24)
+      .setSdkVersion(0x0008) // uiMode requires froyo
+      .Build();
+  EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+  ASSERT_TRUE(ParseSplitParameter(":sw1920dp",
+                                  diagnostics, &path, &constraints));
+  expected_configuration = test::ConfigDescriptionBuilder()
+      .setSmallestScreenWidthDp(0x0780)
+      .setSdkVersion(0x000D) // smallestScreenWidthDp requires honeycomb mr2
+      .Build();
+  EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+  // ========== Test SCREEN_SIZE_DP ==========
+  // screenWidthDp: 'w[0-9]dp'
+  // screenHeightDp: 'h[0-9]dp'
+  ASSERT_TRUE(ParseSplitParameter(":w1920dp",
+                                  diagnostics, &path, &constraints));
+  expected_configuration = test::ConfigDescriptionBuilder()
+      .setScreenWidthDp(0x0780)
+      .setSdkVersion(0x000D) // screenWidthDp requires honeycomb mr2
+      .Build();
+  EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+  ASSERT_TRUE(ParseSplitParameter(":h1080dp",
+                                  diagnostics, &path, &constraints));
+  expected_configuration = test::ConfigDescriptionBuilder()
+      .setScreenHeightDp(0x0438)
+      .setSdkVersion(0x000D) // screenHeightDp requires honeycomb mr2
+      .Build();
+  EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+  // ========== Test SCREEN_CONFIG_2 ==========
+  // screenLayout2: '(round|notround)'
+  // colorMode: '(widecg|nowidecg)'
+  // colorMode: '(highhdr|lowdr)'
+  ASSERT_TRUE(ParseSplitParameter(":round",
+                                  diagnostics, &path, &constraints));
+  expected_configuration = test::ConfigDescriptionBuilder()
+      .setScreenLayout2(0x02)
+      .setSdkVersion(0x0017) // screenLayout2 (round) requires marshmallow
+      .Build();
+  EXPECT_CONFIG_EQ(constraints, expected_configuration);
+
+  ASSERT_TRUE(ParseSplitParameter(":widecg-highdr",
+                                  diagnostics, &path, &constraints));
+  expected_configuration = test::ConfigDescriptionBuilder()
+      .setColorMode(0x0A)
+      .setSdkVersion(0x001A) // colorMode (hdr|colour gamut) requires oreo
+      .Build();
+  EXPECT_CONFIG_EQ(constraints, expected_configuration);
+}
+
+TEST (UtilTest, AdjustSplitConstraintsForMinSdk) {
+  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+
+  IDiagnostics* diagnostics = context.get()->GetDiagnostics();
+  std::vector<SplitConstraints> test_constraints;
+  std::string path;
+
+  test_constraints.push_back({});
+  ASSERT_TRUE(ParseSplitParameter(":v7",
+                                  diagnostics, &path, &test_constraints.back()));
+  test_constraints.push_back({});
+  ASSERT_TRUE(ParseSplitParameter(":xhdpi",
+                                  diagnostics, &path, &test_constraints.back()));
+  EXPECT_EQ(test_constraints.size(), 2);
+  EXPECT_EQ(test_constraints[0].name, "v7");
+  EXPECT_EQ(test_constraints[0].configs.size(), 1);
+  EXPECT_NE(*test_constraints[0].configs.begin(), ConfigDescription::DefaultConfig());
+  EXPECT_EQ(test_constraints[1].name, "xhdpi");
+  EXPECT_EQ(test_constraints[1].configs.size(), 1);
+  EXPECT_NE(*test_constraints[0].configs.begin(), ConfigDescription::DefaultConfig());
+
+  auto adjusted_contraints = AdjustSplitConstraintsForMinSdk(26, test_constraints);
+  EXPECT_EQ(adjusted_contraints.size(), 2);
+  EXPECT_EQ(adjusted_contraints[0].name, "v7");
+  EXPECT_EQ(adjusted_contraints[0].configs.size(), 0);
+  EXPECT_EQ(adjusted_contraints[1].name, "xhdpi");
+  EXPECT_EQ(adjusted_contraints[1].configs.size(), 1);
+  EXPECT_NE(*adjusted_contraints[1].configs.begin(), ConfigDescription::DefaultConfig());
+}
+
 }  // namespace aapt
diff --git a/tools/aapt2/compile/XmlIdCollector.cpp b/tools/aapt2/compile/XmlIdCollector.cpp
index d61a15a..2199d00 100644
--- a/tools/aapt2/compile/XmlIdCollector.cpp
+++ b/tools/aapt2/compile/XmlIdCollector.cpp
@@ -21,6 +21,7 @@
 
 #include "ResourceUtils.h"
 #include "ResourceValues.h"
+#include "text/Unicode.h"
 #include "xml/XmlDom.h"
 
 namespace aapt {
@@ -35,8 +36,9 @@
  public:
   using xml::Visitor::Visit;
 
-  explicit IdCollector(std::vector<SourcedResourceName>* out_symbols)
-      : out_symbols_(out_symbols) {}
+  explicit IdCollector(std::vector<SourcedResourceName>* out_symbols,
+                       SourcePathDiagnostics* source_diag) : out_symbols_(out_symbols),
+                                                             source_diag_(source_diag) {}
 
   void Visit(xml::Element* element) override {
     for (xml::Attribute& attr : element->attributes) {
@@ -44,12 +46,16 @@
       bool create = false;
       if (ResourceUtils::ParseReference(attr.value, &name, &create, nullptr)) {
         if (create && name.type == ResourceType::kId) {
-          auto iter = std::lower_bound(out_symbols_->begin(),
-                                       out_symbols_->end(), name, cmp_name);
-          if (iter == out_symbols_->end() || iter->name != name) {
-            out_symbols_->insert(iter,
-                                 SourcedResourceName{name.ToResourceName(),
-                                                     element->line_number});
+          if (!text::IsValidResourceEntryName(name.entry)) {
+            source_diag_->Error(DiagMessage(element->line_number)
+                                   << "id '" << name << "' has an invalid entry name");
+          } else {
+            auto iter = std::lower_bound(out_symbols_->begin(),
+                                         out_symbols_->end(), name, cmp_name);
+            if (iter == out_symbols_->end() || iter->name != name) {
+              out_symbols_->insert(iter, SourcedResourceName{name.ToResourceName(),
+                                                             element->line_number});
+            }
           }
         }
       }
@@ -60,15 +66,17 @@
 
  private:
   std::vector<SourcedResourceName>* out_symbols_;
+  SourcePathDiagnostics* source_diag_;
 };
 
 }  // namespace
 
 bool XmlIdCollector::Consume(IAaptContext* context, xml::XmlResource* xmlRes) {
   xmlRes->file.exported_symbols.clear();
-  IdCollector collector(&xmlRes->file.exported_symbols);
+  SourcePathDiagnostics source_diag(xmlRes->file.source, context->GetDiagnostics());
+  IdCollector collector(&xmlRes->file.exported_symbols, &source_diag);
   xmlRes->root->Accept(&collector);
-  return true;
+  return !source_diag.HadError();
 }
 
 }  // namespace aapt
diff --git a/tools/aapt2/compile/XmlIdCollector_test.cpp b/tools/aapt2/compile/XmlIdCollector_test.cpp
index 98da56d..d49af3b 100644
--- a/tools/aapt2/compile/XmlIdCollector_test.cpp
+++ b/tools/aapt2/compile/XmlIdCollector_test.cpp
@@ -64,4 +64,14 @@
   EXPECT_TRUE(doc->file.exported_symbols.empty());
 }
 
+TEST(XmlIdCollectorTest, ErrorOnInvalidIds) {
+  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+
+  std::unique_ptr<xml::XmlResource> doc =
+      test::BuildXmlDom("<View foo=\"@+id/foo$bar\"/>");
+
+  XmlIdCollector collector;
+  ASSERT_FALSE(collector.Consume(context.get(), doc.get()));
+}
+
 }  // namespace aapt
diff --git a/tools/aapt2/development.md b/tools/aapt2/development.md
new file mode 100644
index 0000000..8ee873a
--- /dev/null
+++ b/tools/aapt2/development.md
@@ -0,0 +1,11 @@
+# AAPT2 development
+
+## Building
+All build targets can be found in `Android.bp` file. The main ones are `make -j aapt2` and `make -j aapt2_tests`
+
+`make -j aapt2` will create an aapt2 executable in `out/host/linux-x86/bin/aapt2` (on Linux). This `aapt2` executable will then be used for all the apps in the platform.
+
+Static version of the tool (without shared libraries) can be built with `make -j static_sdk_tools dist DIST_DIR=$OUTPUT_DIRECTORY BUILD_HOST_static=1`. Note, in addition to aapt2 this command will also output other statically built tools to the `$OUTPUT_DIRECTORY`.
+
+## Running tests
+Build `make -j aapt2_tests` and then (on Linux) execute `out/host/linux-x86/nativetest64/aapt2_tests/aapt2_tests`
\ No newline at end of file
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
new file mode 100644
index 0000000..2c356d1
--- /dev/null
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -0,0 +1,2197 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DumpManifest.h"
+
+#include "LoadedApk.h"
+#include "SdkConstants.h"
+#include "ValueVisitor.h"
+#include "io/File.h"
+#include "io/FileStream.h"
+#include "process/IResourceTableConsumer.h"
+#include "xml/XmlDom.h"
+
+using ::android::base::StringPrintf;
+
+namespace aapt {
+
+/**
+ * These are attribute resource constants for the platform, as found in android.R.attr.
+ */
+enum {
+  LABEL_ATTR = 0x01010001,
+  ICON_ATTR = 0x01010002,
+  NAME_ATTR = 0x01010003,
+  PERMISSION_ATTR = 0x01010006,
+  EXPORTED_ATTR = 0x01010010,
+  GRANT_URI_PERMISSIONS_ATTR = 0x0101001b,
+  RESOURCE_ATTR = 0x01010025,
+  DEBUGGABLE_ATTR = 0x0101000f,
+  VALUE_ATTR = 0x01010024,
+  VERSION_CODE_ATTR = 0x0101021b,
+  VERSION_NAME_ATTR = 0x0101021c,
+  SCREEN_ORIENTATION_ATTR = 0x0101001e,
+  MIN_SDK_VERSION_ATTR = 0x0101020c,
+  MAX_SDK_VERSION_ATTR = 0x01010271,
+  REQ_TOUCH_SCREEN_ATTR = 0x01010227,
+  REQ_KEYBOARD_TYPE_ATTR = 0x01010228,
+  REQ_HARD_KEYBOARD_ATTR = 0x01010229,
+  REQ_NAVIGATION_ATTR = 0x0101022a,
+  REQ_FIVE_WAY_NAV_ATTR = 0x01010232,
+  TARGET_SDK_VERSION_ATTR = 0x01010270,
+  TEST_ONLY_ATTR = 0x01010272,
+  ANY_DENSITY_ATTR = 0x0101026c,
+  GL_ES_VERSION_ATTR = 0x01010281,
+  SMALL_SCREEN_ATTR = 0x01010284,
+  NORMAL_SCREEN_ATTR = 0x01010285,
+  LARGE_SCREEN_ATTR = 0x01010286,
+  XLARGE_SCREEN_ATTR = 0x010102bf,
+  REQUIRED_ATTR = 0x0101028e,
+  INSTALL_LOCATION_ATTR = 0x010102b7,
+  SCREEN_SIZE_ATTR = 0x010102ca,
+  SCREEN_DENSITY_ATTR = 0x010102cb,
+  REQUIRES_SMALLEST_WIDTH_DP_ATTR = 0x01010364,
+  COMPATIBLE_WIDTH_LIMIT_DP_ATTR = 0x01010365,
+  LARGEST_WIDTH_LIMIT_DP_ATTR = 0x01010366,
+  PUBLIC_KEY_ATTR = 0x010103a6,
+  CATEGORY_ATTR = 0x010103e8,
+  BANNER_ATTR = 0x10103f2,
+  ISGAME_ATTR = 0x10103f4,
+  REQUIRED_FEATURE_ATTR = 0x1010557,
+  REQUIRED_NOT_FEATURE_ATTR = 0x1010558,
+  COMPILE_SDK_VERSION_ATTR = 0x01010572,
+  COMPILE_SDK_VERSION_CODENAME_ATTR = 0x01010573,
+};
+
+const std::string& kAndroidNamespace = "http://schemas.android.com/apk/res/android";
+
+/** Retrieves the attribute of the element with the specified attribute resource id. */
+static xml::Attribute* FindAttribute(xml::Element *el, uint32_t resd_id) {
+  for (auto& a : el->attributes) {
+    if (a.compiled_attribute && a.compiled_attribute.value().id) {
+      if (a.compiled_attribute.value().id.value() == resd_id) {
+        return std::move(&a);
+      }
+    }
+  }
+  return nullptr;
+}
+
+/** Retrieves the attribute of the element that has the specified namespace and attribute name. */
+static xml::Attribute* FindAttribute(xml::Element *el, const std::string &package,
+                                     const std::string &name) {
+  return el->FindAttribute(package, name);
+}
+
+class CommonFeatureGroup;
+
+class ManifestExtractor {
+ public:
+  struct Options {
+    /** Include meta information from <meta-data> elements in the output. */
+    bool include_meta_data = false;
+
+    /** Only output permission information. */
+    bool only_permissions = false;
+  };
+
+  explicit ManifestExtractor(LoadedApk* apk, ManifestExtractor::Options options)
+      : apk_(apk), options_(options) { }
+
+  class Element {
+   public:
+    Element() = default;
+    virtual ~Element() = default;
+
+    static std::unique_ptr<Element> Inflate(ManifestExtractor* extractor, xml::Element* el);
+
+    /** Writes out the extracted contents of the element. */
+    virtual void Print(text::Printer& printer) { }
+
+    /** Adds an element to the list of children of the element. */
+    void AddChild(std::unique_ptr<Element>& child) { children_.push_back(std::move(child)); }
+
+    /** Retrieves the list of children of the element. */
+    const std::vector<std::unique_ptr<Element>>& children() const {
+      return children_;
+    }
+
+    /** Retrieves the extracted xml element tag. */
+    const std::string tag() const {
+      return tag_;
+    }
+
+   protected:
+    ManifestExtractor* extractor() const {
+      return extractor_;
+    }
+
+    /** Retrieves and stores the information extracted from the xml element. */
+    virtual void Extract(xml::Element* el) { }
+
+    /*
+     * Retrieves a configuration value of the resource entry that best matches the specified
+     * configuration.
+     */
+    static Value* BestConfigValue(ResourceEntry* entry,
+                                  const ConfigDescription& match) {
+      if (!entry) {
+        return nullptr;
+      }
+
+      // Determine the config that best matches the desired config
+      ResourceConfigValue* best_value = nullptr;
+      for (auto& value : entry->values) {
+        if (!value->config.match(match)) {
+          continue;
+        }
+
+        if (best_value != nullptr) {
+          if (!value->config.isBetterThan(best_value->config, &match)) {
+            if (value->config.compare(best_value->config) != 0) {
+              continue;
+            }
+          }
+        }
+
+        best_value = value.get();
+      }
+
+      // The entry has no values
+      if (!best_value) {
+        return nullptr;
+      }
+
+      return best_value->value.get();
+    }
+
+    /** Retrieves the resource assigned to the specified resource id if one exists. */
+    Value* FindValueById(const ResourceTable* table, const ResourceId& res_id,
+                         const ConfigDescription& config = DummyConfig()) {
+      if (table) {
+        for (auto& package : table->packages) {
+          if (package->id && package->id.value() == res_id.package_id()) {
+            for (auto& type : package->types) {
+              if (type->id && type->id.value() == res_id.type_id()) {
+                for (auto& entry : type->entries) {
+                  if (entry->id && entry->id.value() == res_id.entry_id()) {
+                    if (auto value = BestConfigValue(entry.get(), config)) {
+                      return value;
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+      return nullptr;
+    }
+
+    /** Attempts to resolve the reference to a non-reference value. */
+    Value* ResolveReference(Reference* ref, const ConfigDescription& config = DummyConfig()) {
+      const int kMaxIterations = 40;
+      int i = 0;
+      while (ref && ref->id && i++ < kMaxIterations) {
+        auto table = extractor_->apk_->GetResourceTable();
+        if (auto value = FindValueById(table, ref->id.value(), config)) {
+          if (ValueCast<Reference>(value)) {
+            ref = ValueCast<Reference>(value);
+          } else {
+            return value;
+          }
+        }
+      }
+      return nullptr;
+    }
+
+    /**
+     * Retrieves the integer value of the attribute . If the value of the attribute is a reference,
+     * this will attempt to resolve the reference to an integer value.
+     **/
+    int32_t* GetAttributeInteger(xml::Attribute* attr,
+                                 const ConfigDescription& config = DummyConfig()) {
+      if (attr != nullptr) {
+        if (attr->compiled_value) {
+          // Resolve references using the dummy configuration
+          Value* value = attr->compiled_value.get();
+          if (ValueCast<Reference>(value)) {
+            value = ResolveReference(ValueCast<Reference>(value), config);
+          } else {
+            value = attr->compiled_value.get();
+          }
+          // Retrieve the integer data if possible
+          if (value != nullptr) {
+            if (BinaryPrimitive* intValue = ValueCast<BinaryPrimitive>(value)) {
+              return (int32_t*) &intValue->value.data;
+            }
+          }
+        }
+      }
+      return nullptr;
+    }
+
+    /**
+     * A version of GetAttributeInteger that returns a default integer if the attribute does not
+     * exist or cannot be resolved to an integer value.
+     **/
+    int32_t GetAttributeIntegerDefault(xml::Attribute* attr, int32_t def,
+                                       const ConfigDescription& config = DummyConfig()) {
+      auto value = GetAttributeInteger(attr, config);
+      if (value) {
+        return *value;
+      }
+      return def;
+    }
+
+    /**
+     * Retrieves the string value of the attribute. If the value of the attribute is a reference,
+     * this will attempt to resolve the reference to a string value.
+     **/
+    const std::string* GetAttributeString(xml::Attribute* attr,
+                                          const ConfigDescription& config = DummyConfig()) {
+      if (attr != nullptr) {
+        if (attr->compiled_value) {
+          // Resolve references using the dummy configuration
+          Value* value = attr->compiled_value.get();
+          if (ValueCast<Reference>(value)) {
+            value = ResolveReference(ValueCast<Reference>(value), config);
+          } else {
+            value = attr->compiled_value.get();
+          }
+
+          // Retrieve the string data of the value if possible
+          if (value != nullptr) {
+            if (String* intValue = ValueCast<String>(value)) {
+              return &(*intValue->value);
+            } else if (RawString* rawValue = ValueCast<RawString>(value)) {
+              return &(*rawValue->value);
+            } else if (FileReference* strValue = ValueCast<FileReference>(value)) {
+              return &(*strValue->path);
+            }
+          }
+        }
+        return &attr->value;
+      }
+      return nullptr;
+    }
+
+    /**
+     * A version of GetAttributeString that returns a default string if the attribute does not
+     * exist or cannot be resolved to an string value.
+     **/
+    std::string GetAttributeStringDefault(xml::Attribute* attr, std::string def,
+                                          const ConfigDescription& config = DummyConfig()) {
+      auto value = GetAttributeString(attr, config);
+      if (value) {
+        return *value;
+      }
+      return def;
+    }
+
+   private:
+      ManifestExtractor* extractor_;
+      std::vector<std::unique_ptr<Element>> children_;
+      std::string tag_;
+  };
+
+  friend Element;
+
+  /** Creates a default configuration used to retrieve resources. */
+  static ConfigDescription DummyConfig() {
+    ConfigDescription config;
+    config.orientation = android::ResTable_config::ORIENTATION_PORT;
+    config.density = android::ResTable_config::DENSITY_MEDIUM;
+    config.sdkVersion = 10000; // Very high.
+    config.screenWidthDp = 320;
+    config.screenHeightDp = 480;
+    config.smallestScreenWidthDp = 320;
+    config.screenLayout |= android::ResTable_config::SCREENSIZE_NORMAL;
+    return config;
+  }
+
+  bool Dump(text::Printer& printer, IDiagnostics* diag);
+
+  /** Recursively visit the xml element tree and return a processed badging element tree. */
+  std::unique_ptr<Element> Visit(xml::Element* element);
+
+    /** Raises the target sdk value if the min target is greater than the current target. */
+  void RaiseTargetSdk(int32_t min_target) {
+    if (min_target > target_sdk_) {
+      target_sdk_ = min_target;
+    }
+  }
+
+  /**
+   * Retrieves the default feature group that features are added into when <uses-feature>
+   * are not in a <feature-group> element.
+   **/
+  CommonFeatureGroup* GetCommonFeatureGroup() {
+    return commonFeatureGroup_.get();
+  }
+
+  /**
+   * Retrieves a mapping of density values to Configurations for retrieving resources that would be
+   * used for that density setting.
+   **/
+  const std::map<uint16_t, ConfigDescription> densities() const {
+    return densities_;
+  }
+
+  /**
+   * Retrieves a mapping of locale BCP 47 strings to Configurations for retrieving resources that
+   * would be used for that locale setting.
+   **/
+  const std::map<std::string, ConfigDescription> locales() const {
+    return locales_;
+  }
+
+  /** Retrieves the current stack of parent during data extraction. */
+  const std::vector<Element*> parent_stack() const {
+    return parent_stack_;
+  }
+
+  int32_t target_sdk() const {
+    return target_sdk_;
+  }
+
+  LoadedApk* const apk_;
+  const Options options_;
+
+ private:
+  std::unique_ptr<CommonFeatureGroup> commonFeatureGroup_ = util::make_unique<CommonFeatureGroup>();
+  std::map<std::string, ConfigDescription> locales_;
+  std::map<uint16_t, ConfigDescription> densities_;
+  std::vector<Element*> parent_stack_;
+  int32_t target_sdk_ = 0;
+};
+
+template<typename T> T* ElementCast(ManifestExtractor::Element* element);
+
+/** Recurs through the children of the specified root in depth-first order. */
+static void ForEachChild(ManifestExtractor::Element* root,
+                         std::function<void(ManifestExtractor::Element*)> f) {
+  for (auto& child : root->children()) {
+    f(child.get());
+    ForEachChild(child.get(), f);
+  }
+}
+
+/**
+ * Checks the element and its recursive children for an element that makes the specified
+ * conditional function return true. Returns the first element that makes the conditional function
+ * return true.
+ **/
+static ManifestExtractor::Element* FindElement(ManifestExtractor::Element* root,
+                                              std::function<bool(ManifestExtractor::Element*)> f) {
+  if (f(root)) {
+    return root;
+  }
+  for (auto& child : root->children()) {
+    if (auto b2 = FindElement(child.get(), f)) {
+      return b2;
+    }
+  }
+  return nullptr;
+}
+
+/** Represents the <manifest> elements **/
+class Manifest : public ManifestExtractor::Element {
+ public:
+  Manifest() = default;
+  std::string package;
+  int32_t versionCode;
+  std::string versionName;
+  const std::string* split = nullptr;
+  const std::string* platformVersionName = nullptr;
+  const std::string* platformVersionCode = nullptr;
+  const int32_t* compilesdkVersion = nullptr;
+  const std::string* compilesdkVersionCodename = nullptr;
+  const int32_t* installLocation = nullptr;
+
+  void Extract(xml::Element* manifest) override {
+    package = GetAttributeStringDefault(FindAttribute(manifest, {}, "package"), "");
+    versionCode = GetAttributeIntegerDefault(FindAttribute(manifest, VERSION_CODE_ATTR), 0);
+    versionName = GetAttributeStringDefault(FindAttribute(manifest, VERSION_NAME_ATTR), "");
+    split = GetAttributeString(FindAttribute(manifest, {}, "split"));
+
+    // Extract the platform build info
+    platformVersionName = GetAttributeString(FindAttribute(manifest, {},
+                                                           "platformBuildVersionName"));
+    platformVersionCode = GetAttributeString(FindAttribute(manifest, {},
+                                                           "platformBuildVersionCode"));
+
+    // Extract the compile sdk info
+    compilesdkVersion = GetAttributeInteger(FindAttribute(manifest, COMPILE_SDK_VERSION_ATTR));
+    compilesdkVersionCodename = GetAttributeString(
+        FindAttribute(manifest, COMPILE_SDK_VERSION_CODENAME_ATTR));
+    installLocation = GetAttributeInteger(FindAttribute(manifest, INSTALL_LOCATION_ATTR));
+  }
+
+  void Print(text::Printer& printer) override {
+    printer.Print(StringPrintf("package: name='%s' ", package.data()));
+    printer.Print(StringPrintf("versionCode='%s' ",
+                               (versionCode > 0) ? std::to_string(versionCode).data() : ""));
+    printer.Print(StringPrintf("versionName='%s'", versionName.data()));
+
+    if (split) {
+      printer.Print(StringPrintf(" split='%s'", split->data()));
+    }
+    if (platformVersionName) {
+      printer.Print(StringPrintf(" platformBuildVersionName='%s'", platformVersionName->data()));
+    }
+    if (platformVersionCode) {
+      printer.Print(StringPrintf(" platformBuildVersionCode='%s'", platformVersionCode->data()));
+    }
+    if (compilesdkVersion) {
+      printer.Print(StringPrintf(" compileSdkVersion='%d'", *compilesdkVersion));
+    }
+    if (compilesdkVersionCodename) {
+      printer.Print(StringPrintf(" compileSdkVersionCodename='%s'",
+                                 compilesdkVersionCodename->data()));
+    }
+    printer.Print("\n");
+
+    if (installLocation) {
+      switch (*installLocation) {
+        case 0:
+          printer.Print("install-location:'auto'\n");
+          break;
+        case 1:
+          printer.Print("install-location:'internalOnly'\n");
+          break;
+        case 2:
+          printer.Print("install-location:'preferExternal'\n");
+          break;
+        default:
+          break;
+      }
+    }
+  }
+};
+
+/** Represents <application> elements. **/
+class Application : public ManifestExtractor::Element {
+ public:
+  Application() = default;
+  std::string label;
+  std::string icon;
+  std::string banner;
+  int32_t is_game;
+  int32_t debuggable;
+  int32_t test_only;
+  bool has_multi_arch;
+
+  /** Mapping from locales to app names. */
+  std::map<std::string, std::string> locale_labels;
+
+  /** Mapping from densities to app icons. */
+  std::map<uint16_t, std::string> density_icons;
+
+  void Extract(xml::Element* element) override {
+    label = GetAttributeStringDefault(FindAttribute(element, LABEL_ATTR), "");
+    icon = GetAttributeStringDefault(FindAttribute(element, ICON_ATTR), "");
+    test_only = GetAttributeIntegerDefault(FindAttribute(element, TEST_ONLY_ATTR), 0);
+    banner = GetAttributeStringDefault(FindAttribute(element, BANNER_ATTR), "");
+    is_game = GetAttributeIntegerDefault(FindAttribute(element, ISGAME_ATTR), 0);
+    debuggable = GetAttributeIntegerDefault(FindAttribute(element, DEBUGGABLE_ATTR), 0);
+
+    // We must search by name because the multiArch flag hasn't been API
+    // frozen yet.
+    has_multi_arch = (GetAttributeIntegerDefault(
+        FindAttribute(element, kAndroidNamespace, "multiArch"), 0) != 0);
+
+    // Retrieve the app names for every locale the app supports
+    auto attr = FindAttribute(element, LABEL_ATTR);
+    for (auto& config : extractor()->locales()) {
+      if (auto label = GetAttributeString(attr, config.second)) {
+        if (label) {
+          locale_labels.insert(std::make_pair(config.first, *label));
+        }
+      }
+    }
+
+    // Retrieve the icons for the densities the app supports
+    attr = FindAttribute(element, ICON_ATTR);
+    for (auto& config : extractor()->densities()) {
+      if (auto resource = GetAttributeString(attr, config.second)) {
+        if (resource) {
+          density_icons.insert(std::make_pair(config.first, *resource));
+        }
+      }
+    }
+  }
+
+  void Print(text::Printer& printer) override {
+    // Print the labels for every locale
+    for (auto p : locale_labels) {
+      if (p.first.empty()) {
+        printer.Print(StringPrintf("application-label:'%s'\n",
+                                    android::ResTable::normalizeForOutput(p.second.data())
+                                        .c_str()));
+      } else {
+        printer.Print(StringPrintf("application-label-%s:'%s'\n", p.first.data(),
+                                    android::ResTable::normalizeForOutput(p.second.data())
+                                        .c_str()));
+      }
+    }
+
+    // Print the icon paths for every density
+    for (auto p : density_icons) {
+      printer.Print(StringPrintf("application-icon-%d:'%s'\n", p.first, p.second.data()));
+    }
+
+    // Print the application info
+    printer.Print(StringPrintf("application: label='%s' ",
+                                android::ResTable::normalizeForOutput(label.data()).c_str()));
+    printer.Print(StringPrintf("icon='%s'", icon.data()));
+    if (!banner.empty()) {
+      printer.Print(StringPrintf(" banner='%s'", banner.data()));
+    }
+    printer.Print("\n");
+
+    if (test_only != 0) {
+      printer.Print(StringPrintf("testOnly='%d'\n", test_only));
+    }
+    if (is_game != 0) {
+      printer.Print("application-isGame\n");
+    }
+    if (debuggable != 0) {
+      printer.Print("application-debuggable\n");
+    }
+  }
+};
+
+/** Represents <uses-sdk> elements. **/
+class UsesSdkBadging : public ManifestExtractor::Element {
+ public:
+  UsesSdkBadging() = default;
+  const int32_t* min_sdk = nullptr;
+  const std::string* min_sdk_name = nullptr;
+  const int32_t* max_sdk = nullptr;
+  const int32_t* target_sdk = nullptr;
+  const std::string* target_sdk_name = nullptr;
+
+  void Extract(xml::Element* element) override {
+    min_sdk = GetAttributeInteger(FindAttribute(element, MIN_SDK_VERSION_ATTR));
+    min_sdk_name = GetAttributeString(FindAttribute(element, MIN_SDK_VERSION_ATTR));
+    max_sdk = GetAttributeInteger(FindAttribute(element, MAX_SDK_VERSION_ATTR));
+    target_sdk = GetAttributeInteger(FindAttribute(element, TARGET_SDK_VERSION_ATTR));
+    target_sdk_name = GetAttributeString(FindAttribute(element, TARGET_SDK_VERSION_ATTR));
+
+    // Detect the target sdk of the element
+    if  ((min_sdk_name && *min_sdk_name == "Donut")
+        || (target_sdk_name && *target_sdk_name == "Donut")) {
+      extractor()->RaiseTargetSdk(4);
+    }
+    if (min_sdk) {
+      extractor()->RaiseTargetSdk(*min_sdk);
+    }
+    if (target_sdk) {
+      extractor()->RaiseTargetSdk(*target_sdk);
+    }
+  }
+
+  void Print(text::Printer& printer) override {
+    if (min_sdk) {
+      printer.Print(StringPrintf("sdkVersion:'%d'\n", *min_sdk));
+    } else if (min_sdk_name) {
+      printer.Print(StringPrintf("sdkVersion:'%s'\n", min_sdk_name->data()));
+    }
+    if (max_sdk) {
+      printer.Print(StringPrintf("maxSdkVersion:'%d'\n", *max_sdk));
+    }
+    if (target_sdk) {
+      printer.Print(StringPrintf("targetSdkVersion:'%d'\n", *target_sdk));
+    } else if (target_sdk_name) {
+      printer.Print(StringPrintf("targetSdkVersion:'%s'\n", target_sdk_name->data()));
+    }
+  }
+};
+
+/** Represents <uses-configuration> elements. **/
+class UsesConfiguarion : public ManifestExtractor::Element {
+ public:
+  UsesConfiguarion() = default;
+  int32_t req_touch_screen = 0;
+  int32_t req_keyboard_type = 0;
+  int32_t req_hard_keyboard = 0;
+  int32_t req_navigation = 0;
+  int32_t req_five_way_nav = 0;
+
+  void Extract(xml::Element* element) override {
+    req_touch_screen = GetAttributeIntegerDefault(
+        FindAttribute(element, REQ_TOUCH_SCREEN_ATTR), 0);
+    req_keyboard_type = GetAttributeIntegerDefault(
+        FindAttribute(element, REQ_KEYBOARD_TYPE_ATTR), 0);
+    req_hard_keyboard = GetAttributeIntegerDefault(
+        FindAttribute(element, REQ_HARD_KEYBOARD_ATTR), 0);
+    req_navigation = GetAttributeIntegerDefault(
+        FindAttribute(element, REQ_NAVIGATION_ATTR), 0);
+    req_five_way_nav = GetAttributeIntegerDefault(
+        FindAttribute(element, REQ_FIVE_WAY_NAV_ATTR), 0);
+  }
+
+  void Print(text::Printer& printer) override {
+    printer.Print("uses-configuration:");
+    if (req_touch_screen != 0) {
+      printer.Print(StringPrintf(" reqTouchScreen='%d'", req_touch_screen));
+    }
+    if (req_keyboard_type != 0) {
+      printer.Print(StringPrintf(" reqKeyboardType='%d'", req_keyboard_type));
+    }
+    if (req_hard_keyboard != 0) {
+      printer.Print(StringPrintf(" reqHardKeyboard='%d'", req_hard_keyboard));
+    }
+    if (req_navigation != 0) {
+      printer.Print(StringPrintf(" reqNavigation='%d'", req_navigation));
+    }
+    if (req_five_way_nav != 0) {
+      printer.Print(StringPrintf(" reqFiveWayNav='%d'", req_five_way_nav));
+    }
+    printer.Print("\n");
+  }
+};
+
+/** Represents <supports-screen> elements. **/
+class SupportsScreen : public ManifestExtractor::Element {
+ public:
+  SupportsScreen() = default;
+  int32_t small_screen = 1;
+  int32_t normal_screen = 1;
+  int32_t large_screen  = 1;
+  int32_t xlarge_screen = 1;
+  int32_t any_density = 1;
+  int32_t requires_smallest_width_dp = 0;
+  int32_t compatible_width_limit_dp = 0;
+  int32_t largest_width_limit_dp = 0;
+
+  void Extract(xml::Element* element) override {
+    small_screen = GetAttributeIntegerDefault(FindAttribute(element, SMALL_SCREEN_ATTR), 1);
+    normal_screen = GetAttributeIntegerDefault(FindAttribute(element, NORMAL_SCREEN_ATTR), 1);
+    large_screen = GetAttributeIntegerDefault(FindAttribute(element, LARGE_SCREEN_ATTR), 1);
+    xlarge_screen = GetAttributeIntegerDefault(FindAttribute(element, XLARGE_SCREEN_ATTR), 1);
+    any_density = GetAttributeIntegerDefault(FindAttribute(element, ANY_DENSITY_ATTR), 1);
+
+    requires_smallest_width_dp = GetAttributeIntegerDefault(
+        FindAttribute(element, REQUIRES_SMALLEST_WIDTH_DP_ATTR), 0);
+    compatible_width_limit_dp = GetAttributeIntegerDefault(
+        FindAttribute(element, COMPATIBLE_WIDTH_LIMIT_DP_ATTR), 0);
+    largest_width_limit_dp = GetAttributeIntegerDefault(
+        FindAttribute(element, LARGEST_WIDTH_LIMIT_DP_ATTR), 0);
+
+    // For modern apps, if screen size buckets haven't been specified
+    // but the new width ranges have, then infer the buckets from them.
+    if (small_screen > 0 && normal_screen > 0 && large_screen > 0 && xlarge_screen > 0
+        && requires_smallest_width_dp > 0) {
+      int32_t compat_width = (compatible_width_limit_dp > 0) ? compatible_width_limit_dp
+                                                             : requires_smallest_width_dp;
+      small_screen = (requires_smallest_width_dp <= 240 && compat_width >= 240) ? -1 : 0;
+      normal_screen = (requires_smallest_width_dp <= 320 && compat_width >= 320) ? -1 : 0;
+      large_screen = (requires_smallest_width_dp <= 480 && compat_width >= 480) ? -1 : 0;
+      xlarge_screen = (requires_smallest_width_dp <= 720 && compat_width >= 720) ? -1 : 0;
+    }
+  }
+
+  void PrintScreens(text::Printer& printer, int32_t target_sdk) {
+    int32_t small_screen_temp = small_screen;
+    int32_t normal_screen_temp  = normal_screen;
+    int32_t large_screen_temp  = large_screen;
+    int32_t xlarge_screen_temp  = xlarge_screen;
+    int32_t any_density_temp  = any_density;
+
+    // Determine default values for any unspecified screen sizes,
+    // based on the target SDK of the package.  As of 4 (donut)
+    // the screen size support was introduced, so all default to
+    // enabled.
+    if (small_screen_temp  > 0) {
+      small_screen_temp  = target_sdk >= 4 ? -1 : 0;
+    }
+    if (normal_screen_temp  > 0) {
+      normal_screen_temp  = -1;
+    }
+    if (large_screen_temp  > 0) {
+      large_screen_temp  = target_sdk >= 4 ? -1 : 0;
+    }
+    if (xlarge_screen_temp  > 0) {
+      // Introduced in Gingerbread.
+      xlarge_screen_temp  = target_sdk >= 9 ? -1 : 0;
+    }
+    if (any_density_temp  > 0) {
+      any_density_temp  = (target_sdk >= 4 || requires_smallest_width_dp > 0
+          || compatible_width_limit_dp > 0) ? -1 : 0;
+    }
+
+    // Print the formatted screen info
+    printer.Print("supports-screens:");
+    if (small_screen_temp  != 0) {
+      printer.Print(" 'small'");
+    }
+    if (normal_screen_temp  != 0) {
+      printer.Print(" 'normal'");
+    }
+    if (large_screen_temp   != 0) {
+      printer.Print(" 'large'");
+    }
+    if (xlarge_screen_temp  != 0) {
+      printer.Print(" 'xlarge'");
+    }
+    printer.Print("\n");
+    printer.Print(StringPrintf("supports-any-density: '%s'\n",
+                                (any_density_temp ) ? "true" : "false"));
+    if (requires_smallest_width_dp > 0) {
+      printer.Print(StringPrintf("requires-smallest-width:'%d'\n", requires_smallest_width_dp));
+    }
+    if (compatible_width_limit_dp > 0) {
+      printer.Print(StringPrintf("compatible-width-limit:'%d'\n", compatible_width_limit_dp));
+    }
+    if (largest_width_limit_dp > 0) {
+      printer.Print(StringPrintf("largest-width-limit:'%d'\n", largest_width_limit_dp));
+    }
+  }
+};
+
+/** Represents <feature-group> elements. **/
+class FeatureGroup : public ManifestExtractor::Element {
+ public:
+  FeatureGroup() = default;
+  std::string label;
+  int32_t open_gles_version = 0;
+
+  void Extract(xml::Element* element) override {
+    label = GetAttributeStringDefault(FindAttribute(element, LABEL_ATTR), "");
+  }
+
+  virtual void PrintGroup(text::Printer& printer) {
+    printer.Print(StringPrintf("feature-group: label='%s'\n", label.data()));
+    if (open_gles_version > 0) {
+      printer.Print(StringPrintf("  uses-gl-es: '0x%x'\n", open_gles_version));
+    }
+
+    for (auto feature : features_) {
+      printer.Print(StringPrintf("  uses-feature%s: name='%s'",
+                                 (feature.second.required ? "" : "-not-required"),
+                                 feature.first.data()));
+      if (feature.second.version > 0) {
+        printer.Print(StringPrintf(" version='%d'", feature.second.version));
+      }
+      printer.Print("\n");
+    }
+  }
+
+  /** Adds a feature to the feature group. */
+  void AddFeature(const std::string& name, bool required = true, int32_t version = -1) {
+    features_.insert(std::make_pair(name, Feature{ required, version }));
+    if (required) {
+      if (name == "android.hardware.camera.autofocus" ||
+          name == "android.hardware.camera.flash") {
+        AddFeature("android.hardware.camera", true);
+      } else if (name == "android.hardware.location.gps" ||
+                 name == "android.hardware.location.network") {
+        AddFeature("android.hardware.location", true);
+      } else if (name == "android.hardware.faketouch.multitouch") {
+        AddFeature("android.hardware.faketouch", true);
+      } else if (name == "android.hardware.faketouch.multitouch.distinct" ||
+                 name == "android.hardware.faketouch.multitouch.jazzhands") {
+        AddFeature("android.hardware.faketouch.multitouch", true);
+        AddFeature("android.hardware.faketouch", true);
+      } else if (name == "android.hardware.touchscreen.multitouch") {
+        AddFeature("android.hardware.touchscreen", true);
+      } else if (name == "android.hardware.touchscreen.multitouch.distinct" ||
+                 name == "android.hardware.touchscreen.multitouch.jazzhands") {
+        AddFeature("android.hardware.touchscreen.multitouch", true);
+        AddFeature("android.hardware.touchscreen", true);
+      } else if (name == "android.hardware.opengles.aep") {
+        const int kOpenGLESVersion31 = 0x00030001;
+        if (kOpenGLESVersion31 > open_gles_version) {
+          open_gles_version = kOpenGLESVersion31;
+        }
+      }
+    }
+  }
+
+  /** Returns true if the feature group has the given feature. */
+  virtual bool HasFeature(const std::string& name) {
+    return features_.find(name) != features_.end();
+  }
+
+  /** Merges the features of another feature group into this group. */
+  void Merge(FeatureGroup* group) {
+    open_gles_version = std::max(open_gles_version, group->open_gles_version);
+    for (auto& feature : group->features_) {
+      features_.insert(feature);
+    }
+  }
+
+ protected:
+  struct Feature {
+   public:
+    bool required = false;
+    int32_t version = -1;
+  };
+
+  /* Mapping of feature names to their properties. */
+  std::map<std::string, Feature> features_;
+};
+
+/**
+ * Represents the default feature group for the application if no <feature-group> elements are
+ * present in the manifest.
+ **/
+class CommonFeatureGroup : public FeatureGroup {
+ public:
+  CommonFeatureGroup() = default;
+  void PrintGroup(text::Printer& printer) override {
+    FeatureGroup::PrintGroup(printer);
+
+    // Also print the implied features
+    for (auto feature : implied_features_) {
+      if (features_.find(feature.first) == features_.end()) {
+        const char* sdk23 = feature.second.implied_from_sdk_k23 ? "-sdk-23" : "";
+        printer.Print(StringPrintf("  uses-feature%s: name='%s'\n", sdk23, feature.first.data()));
+        printer.Print(StringPrintf("  uses-implied-feature%s: name='%s' reason='", sdk23,
+                                    feature.first.data()));
+
+        // Print the reasons as a sentence
+        size_t count = 0;
+        for (auto reason : feature.second.reasons) {
+          printer.Print(reason);
+          if (count + 2 < feature.second.reasons.size()) {
+            printer.Print(", ");
+          } else if (count + 1 < feature.second.reasons.size()) {
+            printer.Print(", and ");
+          }
+          count++;
+        }
+        printer.Print("'\n");
+      }
+    }
+  }
+
+  /** Returns true if the feature group has the given feature. */
+  bool HasFeature(const std::string& name) override {
+    return FeatureGroup::HasFeature(name)
+        || implied_features_.find(name) != implied_features_.end();
+  }
+
+  /** Adds a feature to a set of implied features not explicitly requested in the manifest. */
+  void addImpliedFeature(const std::string& name, const std::string& reason, bool sdk23 = false) {
+    auto entry = implied_features_.find(name);
+    if (entry == implied_features_.end()) {
+      implied_features_.insert(std::make_pair(name, ImpliedFeature(sdk23)));
+      entry = implied_features_.find(name);
+    }
+
+    // A non-sdk 23 implied feature takes precedence.
+    if (entry->second.implied_from_sdk_k23 && !sdk23) {
+      entry->second.implied_from_sdk_k23 = false;
+    }
+
+    entry->second.reasons.insert(reason);
+  }
+
+  /**
+   * Adds a feature to a set of implied features for all features that are implied by the presence
+   * of the permission.
+   **/
+  void addImpliedFeaturesForPermission(int32_t targetSdk, const std::string& name, bool sdk23) {
+    if (name == "android.permission.CAMERA") {
+      addImpliedFeature("android.hardware.camera",
+                        StringPrintf("requested %s permission", name.data()),
+                        sdk23);
+
+    } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
+      if (targetSdk < SDK_LOLLIPOP) {
+        addImpliedFeature("android.hardware.location.gps",
+                          StringPrintf("requested %s permission", name.data()),
+                          sdk23);
+        addImpliedFeature("android.hardware.location.gps",
+                          StringPrintf("targetSdkVersion < %d", SDK_LOLLIPOP),
+                          sdk23);
+      }
+      addImpliedFeature("android.hardware.location",
+                        StringPrintf("requested %s permission", name.data()),
+                        sdk23);
+
+    } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
+      if (targetSdk < SDK_LOLLIPOP) {
+        addImpliedFeature("android.hardware.location.network",
+                          StringPrintf("requested %s permission", name.data()),
+                          sdk23);
+        addImpliedFeature("android.hardware.location.network",
+                          StringPrintf("targetSdkVersion < %d", SDK_LOLLIPOP),
+                          sdk23);
+      }
+      addImpliedFeature("android.hardware.location",
+                        StringPrintf("requested %s permission", name.data()),
+                        sdk23);
+
+    } else if (name == "android.permission.ACCESS_MOCK_LOCATION" ||
+        name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
+        name == "android.permission.INSTALL_LOCATION_PROVIDER") {
+      addImpliedFeature("android.hardware.location",
+                        StringPrintf("requested %s permission", name.data()),
+                        sdk23);
+
+    } else if (name == "android.permission.BLUETOOTH" ||
+        name == "android.permission.BLUETOOTH_ADMIN") {
+      if (targetSdk > SDK_DONUT) {
+        addImpliedFeature("android.hardware.bluetooth",
+                          StringPrintf("requested %s permission", name.data()),
+                          sdk23);
+        addImpliedFeature("android.hardware.bluetooth",
+                          StringPrintf("targetSdkVersion > %d", SDK_DONUT),
+                          sdk23);
+      }
+
+    } else if (name == "android.permission.RECORD_AUDIO") {
+      addImpliedFeature("android.hardware.microphone",
+                        StringPrintf("requested %s permission", name.data()),
+                        sdk23);
+
+    } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
+        name == "android.permission.CHANGE_WIFI_STATE" ||
+        name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
+      addImpliedFeature("android.hardware.wifi",
+                        StringPrintf("requested %s permission", name.data()),
+                        sdk23);
+
+    } else if (name == "android.permission.CALL_PHONE" ||
+        name == "android.permission.CALL_PRIVILEGED" ||
+        name == "android.permission.MODIFY_PHONE_STATE" ||
+        name == "android.permission.PROCESS_OUTGOING_CALLS" ||
+        name == "android.permission.READ_SMS" ||
+        name == "android.permission.RECEIVE_SMS" ||
+        name == "android.permission.RECEIVE_MMS" ||
+        name == "android.permission.RECEIVE_WAP_PUSH" ||
+        name == "android.permission.SEND_SMS" ||
+        name == "android.permission.WRITE_APN_SETTINGS" ||
+        name == "android.permission.WRITE_SMS") {
+      addImpliedFeature("android.hardware.telephony",
+                        "requested a telephony permission",
+                        sdk23);
+    }
+  }
+
+ private:
+  /**
+   * Represents a feature that has been automatically added due to a pre-requisite or for some
+   * other reason.
+   */
+  struct ImpliedFeature {
+    explicit ImpliedFeature(bool sdk23 = false) : implied_from_sdk_k23(sdk23) {}
+
+    /** List of human-readable reasons for why this feature was implied. */
+    std::set<std::string> reasons;
+
+    // Was this implied by a permission from SDK 23 (<uses-permission-sdk-23 />)
+    bool implied_from_sdk_k23;
+  };
+
+  /* Mapping of implied feature names to their properties. */
+  std::map<std::string, ImpliedFeature> implied_features_;
+};
+
+/** Represents <uses-feature> elements. **/
+class UsesFeature : public ManifestExtractor::Element {
+ public:
+  UsesFeature() = default;
+  void Extract(xml::Element* element) override {
+    const std::string* name = GetAttributeString(FindAttribute(element, NAME_ATTR));
+    int32_t* gl = GetAttributeInteger(FindAttribute(element, GL_ES_VERSION_ATTR));
+    bool required = GetAttributeIntegerDefault(
+        FindAttribute(element, REQUIRED_ATTR), true) != 0;
+    int32_t version = GetAttributeIntegerDefault(
+        FindAttribute(element, kAndroidNamespace, "version"), 0);
+
+    // Add the feature to the parent feature group element if one exists; otherwise, add it to the
+    // common feature group
+    FeatureGroup* feature_group = ElementCast<FeatureGroup>(extractor()->parent_stack()[0]);
+    if (!feature_group) {
+      feature_group = extractor()->GetCommonFeatureGroup();
+    } else {
+      // All features in side of <feature-group> elements are required.
+      required = true;
+    }
+
+    if (name) {
+      feature_group->AddFeature(*name, required, version);
+    } else if (gl) {
+      feature_group->open_gles_version = std::max(feature_group->open_gles_version, *gl);
+    }
+  }
+};
+
+/** Represents <uses-permission> elements. **/
+class UsesPermission : public ManifestExtractor::Element {
+ public:
+  UsesPermission() = default;
+  std::string name;
+  std::string requiredFeature;
+  std::string requiredNotFeature;
+  int32_t required = true;
+  int32_t maxSdkVersion = -1;
+
+  void Extract(xml::Element* element) override {
+    name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+    requiredFeature = GetAttributeStringDefault(
+        FindAttribute(element, REQUIRED_FEATURE_ATTR), "");
+    requiredNotFeature = GetAttributeStringDefault(
+        FindAttribute(element, REQUIRED_NOT_FEATURE_ATTR), "");
+    required = GetAttributeIntegerDefault(FindAttribute(element, REQUIRED_ATTR), 1);
+    maxSdkVersion = GetAttributeIntegerDefault(
+        FindAttribute(element, MAX_SDK_VERSION_ATTR), -1);
+
+    if (!name.empty()) {
+      CommonFeatureGroup* common = extractor()->GetCommonFeatureGroup();
+      common->addImpliedFeaturesForPermission(extractor()->target_sdk(), name, false);
+    }
+  }
+
+  void Print(text::Printer& printer) override {
+    if (!name.empty()) {
+      printer.Print(StringPrintf("uses-permission: name='%s'", name.data()));
+      if (maxSdkVersion >= 0) {
+        printer.Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
+      }
+      if (!requiredFeature.empty()) {
+        printer.Print(StringPrintf(" requiredFeature='%s'", requiredFeature.data()));
+      }
+      if (!requiredNotFeature.empty()) {
+        printer.Print(StringPrintf(" requiredNotFeature='%s'", requiredNotFeature.data()));
+      }
+      printer.Print("\n");
+      if (required == 0) {
+        printer.Print(StringPrintf("optional-permission: name='%s'", name.data()));
+        if (maxSdkVersion >= 0) {
+          printer.Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
+        }
+        printer.Print("\n");
+      }
+    }
+  }
+
+  void PrintImplied(text::Printer& printer, const std::string& reason) {
+    printer.Print(StringPrintf("uses-implied-permission: name='%s'", name.data()));
+    if (maxSdkVersion >= 0) {
+      printer.Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
+    }
+    printer.Print(StringPrintf(" reason='%s'\n", reason.data()));
+  }
+};
+
+/** Represents <uses-permission-sdk-23> elements. **/
+class UsesPermissionSdk23 : public ManifestExtractor::Element {
+ public:
+  UsesPermissionSdk23() = default;
+  const std::string* name = nullptr;
+  const int32_t* maxSdkVersion = nullptr;
+
+  void Extract(xml::Element* element) override {
+    name = GetAttributeString(FindAttribute(element, NAME_ATTR));
+    maxSdkVersion = GetAttributeInteger(FindAttribute(element, MAX_SDK_VERSION_ATTR));
+
+    if (name) {
+      CommonFeatureGroup* common = extractor()->GetCommonFeatureGroup();
+      common->addImpliedFeaturesForPermission(extractor()->target_sdk(), *name, true);
+    }
+  }
+
+  void Print(text::Printer& printer) override {
+    if (name) {
+      printer.Print(StringPrintf("uses-permission-sdk-23: name='%s'", name->data()));
+      if (maxSdkVersion) {
+        printer.Print(StringPrintf(" maxSdkVersion='%d'", *maxSdkVersion));
+      }
+      printer.Print("\n");
+    }
+  }
+};
+
+/** Represents <permission> elements. These elements are only printing when dumping permissions. **/
+class Permission : public ManifestExtractor::Element {
+ public:
+  Permission() = default;
+  std::string name;
+
+  void Extract(xml::Element* element) override {
+    name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+  }
+
+  void Print(text::Printer& printer) override {
+    if (extractor()->options_.only_permissions && !name.empty()) {
+      printer.Print(StringPrintf("permission: %s\n", name.data()));
+    }
+  }
+};
+
+/** Represents <activity> elements. **/
+class Activity : public ManifestExtractor::Element {
+ public:
+  Activity() = default;
+  std::string name;
+  std::string icon;
+  std::string label;
+  std::string banner;
+
+  bool has_component_ = false;
+  bool has_launcher_category = false;
+  bool has_leanback_launcher_category = false;
+  bool has_main_action = false;
+
+  void Extract(xml::Element* element) override {
+    name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+    label = GetAttributeStringDefault(FindAttribute(element, LABEL_ATTR), "");
+    icon = GetAttributeStringDefault(FindAttribute(element, ICON_ATTR), "");
+    banner = GetAttributeStringDefault(FindAttribute(element, BANNER_ATTR), "");
+
+    // Retrieve the package name from the manifest
+    std::string package;
+    for (auto& parent : extractor()->parent_stack()) {
+      if (auto manifest = ElementCast<Manifest>(parent)) {
+        package = manifest->package;
+        break;
+      }
+    }
+
+    // Fully qualify the activity name
+    ssize_t idx = name.find(".");
+    if (idx == 0) {
+      name = package + name;
+    } else if (idx < 0) {
+      name = package + "." + name;
+    }
+
+    auto orientation = GetAttributeInteger(FindAttribute(element, SCREEN_ORIENTATION_ATTR));
+    if (orientation) {
+      CommonFeatureGroup* common = extractor()->GetCommonFeatureGroup();
+      int orien = *orientation;
+      if (orien == 0 || orien == 6 || orien == 8) {
+        // Requests landscape, sensorLandscape, or reverseLandscape.
+        common->addImpliedFeature("android.hardware.screen.landscape",
+                                  "one or more activities have specified a landscape orientation",
+                                  false);
+      } else if (orien == 1 || orien == 7 || orien == 9) {
+        // Requests portrait, sensorPortrait, or reversePortrait.
+        common->addImpliedFeature("android.hardware.screen.portrait",
+                                  "one or more activities have specified a portrait orientation",
+                                  false);
+      }
+    }
+  }
+
+  void Print(text::Printer& printer) override {
+    // Print whether the activity has the HOME category and a the MAIN action
+    if (has_main_action && has_launcher_category) {
+      printer.Print("launchable-activity:");
+      if (!name.empty()) {
+        printer.Print(StringPrintf(" name='%s' ", name.data()));
+      }
+      printer.Print(StringPrintf(" label='%s' icon='%s'\n",
+                                  android::ResTable::normalizeForOutput(label.data()).c_str(),
+                                  icon.data()));
+    }
+
+    // Print wether the activity has the HOME category and a the MAIN action
+    if (has_leanback_launcher_category) {
+      printer.Print("leanback-launchable-activity:");
+      if (!name.empty()) {
+        printer.Print(StringPrintf(" name='%s' ", name.data()));
+      }
+      printer.Print(StringPrintf(" label='%s' icon='%s' banner='%s'\n",
+                                  android::ResTable::normalizeForOutput(label.data()).c_str(),
+                                  icon.data(), banner.data()));
+    }
+  }
+};
+
+/** Represents <intent-filter> elements. */
+class IntentFilter : public ManifestExtractor::Element {
+ public:
+  IntentFilter() = default;
+};
+
+/** Represents <category> elements. */
+class Category : public ManifestExtractor::Element {
+ public:
+  Category() = default;
+  std::string component = "";
+
+  void Extract(xml::Element* element) override {
+    const std::string* category = GetAttributeString(FindAttribute(element, NAME_ATTR));
+
+    auto parent_stack = extractor()->parent_stack();
+    if (category && ElementCast<IntentFilter>(parent_stack[0])
+        && ElementCast<Activity>(parent_stack[1])) {
+      Activity* activity = ElementCast<Activity>(parent_stack[1]);
+
+      if (*category == "android.intent.category.LAUNCHER") {
+        activity->has_launcher_category = true;
+      } else if (*category == "android.intent.category.LEANBACK_LAUNCHER") {
+        activity->has_leanback_launcher_category = true;
+      } else if (*category == "android.intent.category.HOME") {
+        component = "launcher";
+      }
+    }
+  }
+};
+
+/**
+ * Represents <provider> elements. The elements may have an <intent-filter> which may have <action>
+ * elements nested within.
+ **/
+class Provider : public ManifestExtractor::Element {
+ public:
+  Provider() = default;
+  bool has_required_saf_attributes = false;
+
+  void Extract(xml::Element* element) override {
+    const int32_t* exported = GetAttributeInteger(FindAttribute(element, EXPORTED_ATTR));
+    const int32_t* grant_uri_permissions = GetAttributeInteger(
+        FindAttribute(element, GRANT_URI_PERMISSIONS_ATTR));
+    const std::string* permission = GetAttributeString(
+        FindAttribute(element, PERMISSION_ATTR));
+
+    has_required_saf_attributes = ((exported && *exported != 0)
+        && (grant_uri_permissions && *grant_uri_permissions != 0)
+        && (permission && *permission == "android.permission.MANAGE_DOCUMENTS"));
+  }
+};
+
+/** Represents <receiver> elements. **/
+class Receiver : public ManifestExtractor::Element {
+ public:
+  Receiver() = default;
+  const std::string* permission = nullptr;
+  bool has_component = false;
+
+  void Extract(xml::Element* element) override {
+    permission = GetAttributeString(FindAttribute(element, PERMISSION_ATTR));
+  }
+};
+
+/**Represents <service> elements. **/
+class Service : public ManifestExtractor::Element {
+ public:
+  Service() = default;
+  const std::string* permission = nullptr;
+  bool has_component = false;
+
+  void Extract(xml::Element* element) override {
+    permission = GetAttributeString(FindAttribute(element, PERMISSION_ATTR));
+  }
+};
+
+/** Represents <uses-library> elements. **/
+class UsesLibrary : public ManifestExtractor::Element {
+ public:
+  UsesLibrary() = default;
+  std::string name;
+  int required;
+
+  void Extract(xml::Element* element) override {
+    auto parent_stack = extractor()->parent_stack();
+    if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
+      name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+      required = GetAttributeIntegerDefault(FindAttribute(element, REQUIRED_ATTR), 1);
+    }
+  }
+
+  void Print(text::Printer& printer) override {
+    if (!name.empty()) {
+      printer.Print(StringPrintf("uses-library%s:'%s'\n",
+                                 (required == 0) ? "-not-required" : "", name.data()));
+    }
+  }
+};
+
+/**
+ * Represents <meta-data> elements. These tags are only printed when a flag is passed in to
+ * explicitly enable meta data printing.
+ **/
+class MetaData : public ManifestExtractor::Element {
+ public:
+  MetaData() = default;
+  std::string name;
+  const std::string* value;
+  const int* value_int;
+  const std::string* resource;
+  const int* resource_int;
+
+  void Extract(xml::Element* element) override {
+    name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+    value = GetAttributeString(FindAttribute(element, VALUE_ATTR));
+    value_int = GetAttributeInteger(FindAttribute(element, VALUE_ATTR));
+    resource = GetAttributeString(FindAttribute(element, RESOURCE_ATTR));
+    resource_int = GetAttributeInteger(FindAttribute(element, RESOURCE_ATTR));
+  }
+
+  void Print(text::Printer& printer) override {
+    if (extractor()->options_.include_meta_data && !name.empty()) {
+      printer.Print(StringPrintf("meta-data: name='%s' ", name.data()));
+      if (value) {
+        printer.Print(StringPrintf("value='%s' ", value->data()));
+      } else if (value_int) {
+        printer.Print(StringPrintf("value='%d' ", *value_int));
+      } else {
+        if (resource) {
+          printer.Print(StringPrintf("resource='%s' ", resource->data()));
+        } else if (resource_int) {
+          printer.Print(StringPrintf("resource='%d' ", *resource_int));
+        }
+      }
+      printer.Print("\n");
+    }
+  }
+};
+
+/**
+ * Represents <action> elements. Detects the presence of certain activity, provider, receiver, and
+ * service components.
+ **/
+class Action : public ManifestExtractor::Element {
+ public:
+  Action() = default;
+  std::string component = "";
+
+  void Extract(xml::Element* element) override {
+    auto parent_stack = extractor()->parent_stack();
+    std::string action = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+
+    if (ElementCast<IntentFilter>(parent_stack[0])) {
+      if (ElementCast<Activity>(parent_stack[1])) {
+        // Detects the presence of a particular type of activity.
+        Activity* activity = ElementCast<Activity>(parent_stack[1]);
+        auto map = std::map<std::string, std::string>({
+            { "android.intent.action.MAIN" , "main" },
+            { "android.intent.action.VIDEO_CAMERA" , "camera" },
+            { "android.intent.action.STILL_IMAGE_CAMERA_SECURE" , "camera-secure" },
+        });
+
+        auto entry = map.find(action);
+        if (entry != map.end()) {
+          component = entry->second;
+          activity->has_component_ = true;
+        }
+
+        if (action == "android.intent.action.MAIN") {
+          activity->has_main_action = true;
+        }
+
+      } else if (ElementCast<Receiver>(parent_stack[1])) {
+        // Detects the presence of a particular type of receiver. If the action requires a
+        // permission, then the receiver element is checked for the permission.
+        Receiver* receiver = ElementCast<Receiver>(parent_stack[1]);
+        auto map = std::map<std::string, std::string>({
+            { "android.appwidget.action.APPWIDGET_UPDATE" , "app-widget" },
+            { "android.app.action.DEVICE_ADMIN_ENABLED" , "device-admin" },
+        });
+
+        auto permissions = std::map<std::string, std::string>({
+            { "android.app.action.DEVICE_ADMIN_ENABLED" , "android.permission.BIND_DEVICE_ADMIN" },
+        });
+
+        auto entry = map.find(action);
+        auto permission = permissions.find(action);
+        if (entry != map.end() && (permission == permissions.end()
+            || (receiver->permission && permission->second == *receiver->permission))) {
+          receiver->has_component = true;
+          component = entry->second;
+        }
+
+      } else if (ElementCast<Service>(parent_stack[1])) {
+        // Detects the presence of a particular type of service. If the action requires a
+        // permission, then the service element is checked for the permission.
+        Service* service = ElementCast<Service>(parent_stack[1]);
+        auto map = std::map<std::string, std::string>({
+            { "android.view.InputMethod" , "ime" },
+            { "android.service.wallpaper.WallpaperService" , "wallpaper" },
+            { "android.accessibilityservice.AccessibilityService" , "accessibility" },
+            { "android.printservice.PrintService" , "print-service" },
+            { "android.nfc.cardemulation.action.HOST_APDU_SERVICE" , "host-apdu" },
+            { "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE" , "offhost-apdu" },
+            { "android.service.notification.NotificationListenerService" ,"notification-listener" },
+            { "android.service.dreams.DreamService" , "dream" },
+        });
+
+        auto permissions = std::map<std::string, std::string>({
+            { "android.accessibilityservice.AccessibilityService" ,
+              "android.permission.BIND_ACCESSIBILITY_SERVICE" },
+            { "android.printservice.PrintService" , "android.permission.BIND_PRINT_SERVICE" },
+            { "android.nfc.cardemulation.action.HOST_APDU_SERVICE" ,
+              "android.permission.BIND_NFC_SERVICE" },
+            { "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE" ,
+              "android.permission.BIND_NFC_SERVICE" },
+            { "android.service.notification.NotificationListenerService" ,
+              "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" },
+            { "android.service.dreams.DreamService" , "android.permission.BIND_DREAM_SERVICE" },
+        });
+
+        auto entry = map.find(action);
+        auto permission = permissions.find(action);
+        if (entry != map.end() && (permission == permissions.end()
+            || (service->permission && permission->second == *service->permission))) {
+          service->has_component= true;
+          component = entry->second;
+        }
+
+      } else if (ElementCast<Provider>(parent_stack[1])) {
+        // Detects the presence of a particular type of receiver. If the provider requires a
+        // permission, then the provider element is checked for the permission.
+        // Detect whether this action
+        Provider* provider = ElementCast<Provider>(parent_stack[1]);
+        if (action == "android.content.action.DOCUMENTS_PROVIDER"
+            && provider->has_required_saf_attributes) {
+          component = "document-provider";
+        }
+      }
+    }
+
+    // Represents a searchable interface
+    if (action == "android.intent.action.SEARCH") {
+      component = "search";
+    }
+  }
+};
+
+/**
+ * Represents <supports-input> elements. The element may have <input-type> elements nested within.
+ **/
+class SupportsInput : public ManifestExtractor::Element {
+ public:
+  SupportsInput() = default;
+  std::vector<std::string> inputs;
+
+  void Print(text::Printer& printer) override {
+    const size_t size = inputs.size();
+    if (size > 0) {
+      printer.Print("supports-input: '");
+      for (size_t i = 0; i < size; i++) {
+        printer.Print(StringPrintf("value='%s' ", inputs[i].data()));
+      }
+      printer.Print("\n");
+    }
+  }
+};
+
+/** Represents <input-type> elements. **/
+class InputType : public ManifestExtractor::Element {
+ public:
+  InputType() = default;
+  void Extract(xml::Element* element) override {
+    auto name = GetAttributeString(FindAttribute(element, NAME_ATTR));
+    auto parent_stack = extractor()->parent_stack();
+
+    // Add the input to the set of supported inputs
+    if (name && ElementCast<SupportsInput>(parent_stack[0])) {
+      SupportsInput* supports = ElementCast<SupportsInput>(parent_stack[0]);
+      supports->inputs.push_back(*name);
+    }
+  }
+};
+
+/** Represents <original-package> elements. **/
+class OriginalPackage : public ManifestExtractor::Element {
+ public:
+  OriginalPackage() = default;
+  const std::string* name = nullptr;
+
+  void Extract(xml::Element* element) override {
+    name = GetAttributeString(FindAttribute(element, NAME_ATTR));
+  }
+
+  void Print(text::Printer& printer) override {
+    if (name) {
+      printer.Print(StringPrintf("original-package:'%s'\n", name->data()));
+    }
+  }
+};
+
+/** * Represents <package-verifier> elements. **/
+class PackageVerifier : public ManifestExtractor::Element {
+ public:
+  PackageVerifier() = default;
+  const std::string* name = nullptr;
+  const std::string* public_key = nullptr;
+
+  void Extract(xml::Element* element) override {
+    name = GetAttributeString(FindAttribute(element, NAME_ATTR));
+    public_key = GetAttributeString(FindAttribute(element, PUBLIC_KEY_ATTR));
+  }
+
+  void Print(text::Printer& printer) override {
+    if (name && public_key) {
+      printer.Print(StringPrintf("package-verifier: name='%s' publicKey='%s'\n",
+                                 name->data(), public_key->data()));
+    }
+  }
+};
+
+/** Represents <uses-package> elements. **/
+class UsesPackage : public ManifestExtractor::Element {
+ public:
+  UsesPackage() = default;
+  const std::string* name = nullptr;
+
+  void Extract(xml::Element* element) override {
+    name = GetAttributeString(FindAttribute(element, NAME_ATTR));
+  }
+
+  void Print(text::Printer& printer) override {
+    if (name) {
+      printer.Print(StringPrintf("uses-package:'%s'\n", name->data()));
+    }
+  }
+};
+
+/** Represents <screen> elements found in <compatible-screens> elements. */
+class Screen : public ManifestExtractor::Element {
+ public:
+  Screen() = default;
+  const int32_t* size = nullptr;
+  const int32_t* density = nullptr;
+
+  void Extract(xml::Element* element) override {
+    size = GetAttributeInteger(FindAttribute(element, SCREEN_SIZE_ATTR));
+    density = GetAttributeInteger(FindAttribute(element, SCREEN_DENSITY_ATTR));
+  }
+};
+
+/**
+ * Represents <compatible-screens> elements. These elements have <screen> elements nested within
+ * that each denote a supported screen size and screen density.
+ **/
+class CompatibleScreens : public ManifestExtractor::Element {
+ public:
+  CompatibleScreens() = default;
+  void Print(text::Printer& printer) override {
+    printer.Print("compatible-screens:");
+
+    bool first = true;
+    ForEachChild(this, [&printer, &first](ManifestExtractor::Element* el){
+      if (auto screen = ElementCast<Screen>(el)) {
+        if (first) {
+          first = false;
+        } else {
+          printer.Print(",");
+        }
+
+        if (screen->size && screen->density) {
+          printer.Print(StringPrintf("'%d/%d'", *screen->size, *screen->density));
+        }
+      }
+    });
+    printer.Print("\n");
+  }
+};
+
+/** Represents <supports-gl-texture> elements. **/
+class SupportsGlTexture : public ManifestExtractor::Element {
+ public:
+  SupportsGlTexture() = default;
+  const std::string* name = nullptr;
+
+  void Extract(xml::Element* element) override {
+    name = GetAttributeString(FindAttribute(element, NAME_ATTR));
+  }
+
+  void Print(text::Printer& printer) override {
+    if (name) {
+      printer.Print(StringPrintf("supports-gl-texture:'%s'\n", name->data()));
+    }
+  }
+};
+
+/** Recursively prints the extracted badging element. */
+static void Print(ManifestExtractor::Element* el, text::Printer& printer) {
+  el->Print(printer);
+  for (auto &child : el->children()) {
+    Print(child.get(), printer);
+  }
+}
+
+bool ManifestExtractor::Dump(text::Printer& printer, IDiagnostics* diag) {
+  // Load the manifest
+  std::unique_ptr<xml::XmlResource> doc = apk_->LoadXml("AndroidManifest.xml", diag);
+  if (doc == nullptr) {
+    diag->Error(DiagMessage() << "failed to find AndroidManifest.xml");
+    return false;
+  }
+
+  xml::Element* element = doc->root.get();
+  if (element->name != "manifest") {
+    diag->Error(DiagMessage() << "manifest does not start with <manifest> tag");
+    return false;
+  }
+
+  // Print only the <uses-permission>, <uses-permission-sdk23>, and <permission> elements if
+  // printing only permission elements is requested
+  if (options_.only_permissions) {
+    std::unique_ptr<ManifestExtractor::Element> manifest_element =
+        ManifestExtractor::Element::Inflate(this, element);
+
+    if (auto manifest = ElementCast<Manifest>(manifest_element.get())) {
+      for (xml::Element* child : element->GetChildElements()) {
+        if (child->name == "uses-permission" || child->name == "uses-permission-sdk-23"
+            || child->name == "permission") {
+          auto permission_element = ManifestExtractor::Element::Inflate(this, child);
+          manifest->AddChild(permission_element);
+        }
+      }
+
+      printer.Print(StringPrintf("package: %s\n", manifest->package.data()));
+      ForEachChild(manifest, [&printer](ManifestExtractor::Element* el) -> void {
+        el->Print(printer);
+      });
+
+      return true;
+    }
+
+    return false;
+  }
+
+  // Collect information about the resource configurations
+  if (apk_->GetResourceTable()) {
+    for (auto &package : apk_->GetResourceTable()->packages) {
+      for (auto &type : package->types) {
+        for (auto &entry : type->entries) {
+          for (auto &value : entry->values) {
+            std::string locale_str = value->config.GetBcp47LanguageTag();
+
+            // Collect all the unique locales of the apk
+            if (locales_.find(locale_str) == locales_.end()) {
+              ConfigDescription config = ManifestExtractor::DummyConfig();
+              config.setBcp47Locale(locale_str.data());
+              locales_.insert(std::make_pair(locale_str, config));
+            }
+
+            // Collect all the unique density of the apk
+            uint16_t density = (value->config.density == 0) ? (uint16_t) 160
+                                                            : value->config.density;
+            if (densities_.find(density) == densities_.end()) {
+              ConfigDescription config = ManifestExtractor::DummyConfig();
+              config.density = density;
+              densities_.insert(std::make_pair(density, config));
+            }
+          }
+        }
+      }
+    }
+  }
+
+  // Extract badging information
+  auto root = Visit(element);
+
+  // Print the elements in order seen
+  Print(root.get(), printer);
+
+  /** Recursively checks the extracted elements for the specified permission. **/
+  auto FindPermission = [&](ManifestExtractor::Element* root,
+                            const std::string& name) -> ManifestExtractor::Element* {
+    return FindElement(root, [&](ManifestExtractor::Element* el) -> bool {
+      if (UsesPermission* permission = ElementCast<UsesPermission>(el)) {
+        return permission->name == name;
+      }
+      return false;
+    });
+  };
+
+  auto PrintPermission = [&printer](const std::string& name, const std::string& reason,
+                                    int32_t max_sdk_version) -> void {
+    auto permission = util::make_unique<UsesPermission>();
+    permission->name = name;
+    permission->maxSdkVersion = max_sdk_version;
+    permission->Print(printer);
+    permission->PrintImplied(printer, reason);
+  };
+
+  // Implied permissions
+  // Pre-1.6 implicitly granted permission compatibility logic
+  CommonFeatureGroup* common_feature_group = GetCommonFeatureGroup();
+  bool insert_write_external = false;
+  auto write_external_permission = ElementCast<UsesPermission>(
+      FindPermission(root.get(), "android.permission.WRITE_EXTERNAL_STORAGE"));
+
+  if (target_sdk() < 4) {
+    if (!write_external_permission) {
+      PrintPermission("android.permission.WRITE_EXTERNAL_STORAGE", "targetSdkVersion < 4", -1);
+      insert_write_external = true;
+    }
+
+    if (!FindPermission(root.get(), "android.permission.READ_PHONE_STATE")) {
+      PrintPermission("android.permission.READ_PHONE_STATE", "targetSdkVersion < 4", -1);
+    }
+  }
+
+  // If the application has requested WRITE_EXTERNAL_STORAGE, we will
+  // force them to always take READ_EXTERNAL_STORAGE as well.  We always
+  // do this (regardless of target API version) because we can't have
+  // an app with write permission but not read permission.
+  auto read_external = FindPermission(root.get(), "android.permission.READ_EXTERNAL_STORAGE");
+  if (!read_external && (insert_write_external || write_external_permission)) {
+    PrintPermission("android.permission.READ_EXTERNAL_STORAGE",
+                    "requested WRITE_EXTERNAL_STORAGE",
+                    (write_external_permission) ? write_external_permission->maxSdkVersion : -1);
+  }
+
+  // Pre-JellyBean call log permission compatibility.
+  if (target_sdk() < 16) {
+    if (!FindPermission(root.get(), "android.permission.READ_CALL_LOG")
+        && FindPermission(root.get(), "android.permission.READ_CONTACTS")) {
+      PrintPermission("android.permission.READ_CALL_LOG",
+                      "targetSdkVersion < 16 and requested READ_CONTACTS", -1);
+    }
+
+    if (!FindPermission(root.get(), "android.permission.WRITE_CALL_LOG")
+        && FindPermission(root.get(), "android.permission.WRITE_CONTACTS")) {
+      PrintPermission("android.permission.WRITE_CALL_LOG",
+                      "targetSdkVersion < 16 and requested WRITE_CONTACTS", -1);
+    }
+  }
+
+  // If the app hasn't declared the touchscreen as a feature requirement (either
+  // directly or implied, required or not), then the faketouch feature is implied.
+  if (!common_feature_group->HasFeature("android.hardware.touchscreen")) {
+    common_feature_group->addImpliedFeature("android.hardware.faketouch",
+                                            "default feature for all apps", false);
+  }
+
+  // Only print the common feature group if no feature group is defined
+  std::vector<FeatureGroup*> feature_groups;
+  ForEachChild(root.get(), [&feature_groups](ManifestExtractor::Element* el) -> void {
+    if (auto feature_group = ElementCast<FeatureGroup>(el)) {
+      feature_groups.push_back(feature_group);
+    }
+  });
+
+  if (feature_groups.empty()) {
+    common_feature_group->PrintGroup(printer);
+  } else {
+    // Merge the common feature group into the feature group
+    for (auto& feature_group : feature_groups) {
+      feature_group->open_gles_version  = std::max(feature_group->open_gles_version,
+                                                   common_feature_group->open_gles_version);
+      feature_group->Merge(common_feature_group);
+      feature_group->PrintGroup(printer);
+    }
+  };
+
+  // Collect the component types of the application
+  std::set<std::string> components;
+  ForEachChild(root.get(), [&components](ManifestExtractor::Element* el) -> void {
+    if (ElementCast<Action>(el)) {
+      auto action = ElementCast<Action>(el);
+      if (!action->component.empty()) {
+        components.insert(action->component);
+        return;
+      }
+    }
+
+    if (ElementCast<Category>(el)) {
+      auto category = ElementCast<Category>(el);
+      if (!category->component.empty()) {
+        components.insert(category->component);
+        return;
+      }
+    }
+  });
+
+  // Check for the payment component
+  auto apk = apk_;
+  ForEachChild(root.get(), [&apk, &components, &diag](ManifestExtractor::Element* el) -> void {
+    if (auto service = ElementCast<Service>(el)) {
+      auto host_apdu_action = ElementCast<Action>(FindElement(service,
+        [&](ManifestExtractor::Element* el) -> bool {
+          if (auto action = ElementCast<Action>(el)) {
+            return (action->component == "host-apdu");
+          }
+          return false;
+      }));
+
+      auto offhost_apdu_action = ElementCast<Action>(FindElement(service,
+        [&](ManifestExtractor::Element* el) -> bool {
+           if (auto action = ElementCast<Action>(el)) {
+             return (action->component == "offhost-apdu");
+           }
+           return false;
+      }));
+
+      ForEachChild(service, [&apk, &components, &diag, &host_apdu_action,
+          &offhost_apdu_action](ManifestExtractor::Element* el) -> void {
+        if (auto meta_data = ElementCast<MetaData>(el)) {
+          if ((meta_data->name == "android.nfc.cardemulation.host_apdu_service" && host_apdu_action)
+              || (meta_data->name == "android.nfc.cardemulation.off_host_apdu_service"
+                  && offhost_apdu_action)) {
+
+            // Attempt to load the resource file
+            if (!meta_data->resource) {
+              return;
+            }
+            auto resource = apk->LoadXml(*meta_data->resource, diag);
+            if (!resource) {
+              return;
+            }
+
+            // Look for the payment category on an <aid-group> element
+            auto& root = resource.get()->root;
+            if ((host_apdu_action && root->name == "host-apdu-service")
+                || (offhost_apdu_action && root->name == "offhost-apdu-service")) {
+
+              for (auto& child : root->GetChildElements()) {
+                if (child->name == "aid-group") {
+                  auto category = FindAttribute(child, CATEGORY_ATTR);
+                  if (category && category->value == "payment") {
+                    components.insert("payment");
+                    return;
+                  }
+                }
+              }
+            }
+          }
+        }
+      });
+    }
+  });
+
+  // Print the components types if they are present
+  auto PrintComponent = [&components, &printer](const std::string& component) -> void {
+    if (components.find(component) != components.end()) {
+      printer.Print(StringPrintf("provides-component:'%s'\n", component.data()));
+    }
+  };
+
+  PrintComponent("app-widget");
+  PrintComponent("device-admin");
+  PrintComponent("ime");
+  PrintComponent("wallpaper");
+  PrintComponent("accessibility");
+  PrintComponent("print-service");
+  PrintComponent("payment");
+  PrintComponent("search");
+  PrintComponent("document-provider");
+  PrintComponent("launcher");
+  PrintComponent("notification-listener");
+  PrintComponent("dream");
+  PrintComponent("camera");
+  PrintComponent("camera-secure");
+
+  // Print presence of main activity
+  if (components.find("main") != components.end()) {
+    printer.Print("main\n");
+  }
+
+  // Print presence of activities, recivers, and services with no special components
+  FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
+    if (auto activity = ElementCast<Activity>(el)) {
+      if (!activity->has_component_) {
+        printer.Print("other-activities\n");
+        return true;
+      }
+    }
+    return false;
+  });
+
+  FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
+    if (auto receiver = ElementCast<Receiver>(el)) {
+      if (!receiver->has_component) {
+        printer.Print("other-receivers\n");
+        return true;
+      }
+    }
+    return false;
+  });
+
+  FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
+    if (auto service = ElementCast<Service>(el)) {
+      if (!service->has_component) {
+        printer.Print("other-services\n");
+        return true;
+      }
+    }
+    return false;
+  });
+
+  // Print the supported screens
+  SupportsScreen* screen = ElementCast<SupportsScreen>(FindElement(root.get(),
+      [&](ManifestExtractor::Element* el) -> bool {
+    return ElementCast<SupportsScreen>(el) != nullptr;
+  }));
+
+  if (screen) {
+    screen->PrintScreens(printer, target_sdk_);
+  } else {
+    // Print the default supported screens
+    SupportsScreen default_screens;
+    default_screens.PrintScreens(printer, target_sdk_);
+  }
+
+  // Print all the unique locales of the apk
+  printer.Print("locales:");
+  for (auto& config : locales_) {
+    if (config.first.empty()) {
+      printer.Print(" '--_--'");
+    } else {
+      printer.Print(StringPrintf(" '%s'", config.first.data()));
+    }
+  }
+  printer.Print("\n");
+
+  // Print all the densities locales of the apk
+  printer.Print("densities:");
+  for (auto& config : densities_) {
+    printer.Print(StringPrintf(" '%d'", config.first));
+  }
+  printer.Print("\n");
+
+  // Print the supported architectures of the app
+  std::set<std::string> architectures;
+  auto it = apk_->GetFileCollection()->Iterator();
+  while (it->HasNext()) {
+    auto file_path = it->Next()->GetSource().path;
+
+
+    size_t pos = file_path.find("lib/");
+    if (pos != std::string::npos) {
+      file_path = file_path.substr(pos + 4);
+      pos = file_path.find("/");
+      if (pos != std::string::npos) {
+        file_path = file_path.substr(0, pos);
+      }
+
+      architectures.insert(file_path);
+    }
+  }
+
+  // Determine if the application has multiArch supports
+  auto has_multi_arch = FindElement(root.get(), [&](ManifestExtractor::Element* el) -> bool {
+    if (auto application = ElementCast<Application>(el)) {
+      return application->has_multi_arch;
+    }
+    return false;
+  });
+
+  bool output_alt_native_code = false;
+  // A multiArch package is one that contains 64-bit and
+  // 32-bit versions of native code and expects 3rd-party
+  // apps to load these native code libraries. Since most
+  // 64-bit systems also support 32-bit apps, the apps
+  // loading this multiArch package's code may be either
+  if (has_multi_arch) {
+    // If this is a multiArch package, report the 64-bit
+    // version only. Then as a separate entry, report the
+    // rest.
+    //
+    // If we report the 32-bit architecture, this APK will
+    // be installed on a 32-bit device, causing a large waste
+    // of bandwidth and disk space. This assumes that
+    // the developer of the multiArch package has also
+    // made a version that is 32-bit only.
+    const std::string kIntel64 = "x86_64";
+    const std::string kArm64 = "arm64-v8a";
+
+    auto arch = architectures.find(kIntel64);
+    if (arch == architectures.end()) {
+      arch = architectures.find(kArm64);
+    }
+
+    if (arch != architectures.end()) {
+      printer.Print(StringPrintf("native-code: '%s'\n", arch->data()));
+      architectures.erase(arch);
+      output_alt_native_code = true;
+    }
+  }
+
+  if (architectures.size() > 0) {
+    if (output_alt_native_code) {
+      printer.Print("alt-");
+    }
+    printer.Print("native-code:");
+    for (auto& arch : architectures) {
+      printer.Print(StringPrintf(" '%s'", arch.data()));
+    }
+    printer.Print("\n");
+  }
+
+  return true;
+}
+
+/**
+ * Returns the element casted to the type if the element is of that type. Otherwise, returns a null
+ * pointer.
+ **/
+template<typename T>
+T* ElementCast(ManifestExtractor::Element* element) {
+  if (element == nullptr) {
+    return nullptr;
+  }
+
+  const std::unordered_map<std::string, bool> kTagCheck = {
+    {"action", std::is_base_of<Action, T>::value},
+    {"activity", std::is_base_of<Activity, T>::value},
+    {"application", std::is_base_of<Application, T>::value},
+    {"category", std::is_base_of<Category, T>::value},
+    {"compatible-screens", std::is_base_of<CompatibleScreens, T>::value},
+    {"feature-group", std::is_base_of<FeatureGroup, T>::value},
+    {"input-type", std::is_base_of<InputType, T>::value},
+    {"intent-filter", std::is_base_of<IntentFilter, T>::value},
+    {"meta-data", std::is_base_of<MetaData, T>::value},
+    {"manifest", std::is_base_of<Manifest, T>::value},
+    {"original-package", std::is_base_of<OriginalPackage, T>::value},
+    {"package-verifier", std::is_base_of<PackageVerifier, T>::value},
+    {"permission", std::is_base_of<Permission, T>::value},
+    {"provider", std::is_base_of<Provider, T>::value},
+    {"receiver", std::is_base_of<Receiver, T>::value},
+    {"screen", std::is_base_of<Screen, T>::value},
+    {"service", std::is_base_of<Service, T>::value},
+    {"supports-gl-texture", std::is_base_of<SupportsGlTexture, T>::value},
+    {"supports-input", std::is_base_of<SupportsInput, T>::value},
+    {"supports-screens", std::is_base_of<SupportsScreen, T>::value},
+    {"uses-configuration", std::is_base_of<UsesConfiguarion, T>::value},
+    {"uses-feature", std::is_base_of<UsesFeature, T>::value},
+    {"uses-permission", std::is_base_of<UsesPermission, T>::value},
+    {"uses-permission-sdk-23", std::is_base_of<UsesPermissionSdk23, T>::value},
+    {"uses-library", std::is_base_of<UsesLibrary, T>::value},
+    {"uses-package", std::is_base_of<UsesPackage, T>::value},
+    {"uses-sdk", std::is_base_of<UsesSdkBadging, T>::value},
+  };
+
+  auto check = kTagCheck.find(element->tag());
+  if (check != kTagCheck.end() && check->second) {
+    return static_cast<T*>(element);
+  }
+  return nullptr;
+}
+
+template<typename T>
+std::unique_ptr<T> CreateType() {
+  return std::move(util::make_unique<T>());
+}
+
+std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Element::Inflate(
+    ManifestExtractor* extractor, xml::Element* el) {
+  const std::unordered_map<std::string,
+                           std::function<std::unique_ptr<ManifestExtractor::Element>()>>
+      kTagCheck = {
+    {"action", &CreateType<Action>},
+    {"activity", &CreateType<Activity>},
+    {"application", &CreateType<Application>},
+    {"category", &CreateType<Category>},
+    {"compatible-screens", &CreateType<CompatibleScreens>},
+    {"feature-group", &CreateType<FeatureGroup>},
+    {"input-type", &CreateType<InputType>},
+    {"intent-filter",&CreateType<IntentFilter>},
+    {"manifest", &CreateType<Manifest>},
+    {"meta-data", &CreateType<MetaData>},
+    {"original-package", &CreateType<OriginalPackage>},
+    {"package-verifier", &CreateType<PackageVerifier>},
+    {"permission", &CreateType<Permission>},
+    {"provider", &CreateType<Provider>},
+    {"receiver", &CreateType<Receiver>},
+    {"screen", &CreateType<Screen>},
+    {"service", &CreateType<Service>},
+    {"supports-gl-texture", &CreateType<SupportsGlTexture>},
+    {"supports-input", &CreateType<SupportsInput>},
+    {"supports-screens", &CreateType<SupportsScreen>},
+    {"uses-configuration", &CreateType<UsesConfiguarion>},
+    {"uses-feature", &CreateType<UsesFeature>},
+    {"uses-permission", &CreateType<UsesPermission>},
+    {"uses-permission-sdk-23", &CreateType<UsesPermissionSdk23>},
+    {"uses-library", &CreateType<UsesLibrary>},
+    {"uses-package", &CreateType<UsesPackage>},
+    {"uses-sdk", &CreateType<UsesSdkBadging>},
+  };
+
+  // Attempt to map the xml tag to a element inflater
+  std::unique_ptr<ManifestExtractor::Element> element;
+  auto check = kTagCheck.find(el->name);
+  if (check != kTagCheck.end()) {
+    element = check->second();
+  } else {
+    element = util::make_unique<ManifestExtractor::Element>();
+  }
+
+  element->extractor_ = extractor;
+  element->tag_ = el->name;
+  element->Extract(el);
+  return element;
+}
+
+std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Visit(xml::Element* el) {
+  auto element = ManifestExtractor::Element::Inflate(this, el);
+  parent_stack_.insert(parent_stack_.begin(), element.get());
+
+  // Process the element and recursively visit the children
+  for (xml::Element* child : el->GetChildElements()) {
+    auto v = Visit(child);
+    element->AddChild(v);
+  }
+
+  parent_stack_.erase(parent_stack_.begin());
+  return element;
+}
+
+// Use a smaller buffer so that there is less latency for dumping to stdout.
+constexpr size_t kStdOutBufferSize = 1024u;
+
+int DumpBadgingCommand::Action(const std::vector<std::string>& args) {
+  if (args.size() < 1) {
+    diag_->Error(DiagMessage() << "No dump apk specified.");
+    return 1;
+  }
+
+  ManifestExtractor::Options options;
+  options.include_meta_data = include_metadata_;
+
+  io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
+  text::Printer printer(&fout);
+  for (auto apk : args) {
+    auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_);
+    if (!loaded_apk) {
+      return 1;
+    }
+
+    ManifestExtractor extractor(loaded_apk.get(), options);
+    extractor.Dump(printer, diag_);
+  }
+
+  return 0;
+}
+
+int DumpPermissionsCommand::Action(const std::vector<std::string>& args) {
+  if (args.size() < 1) {
+    diag_->Error(DiagMessage() << "No dump apk specified.");
+    return 1;
+  }
+
+  ManifestExtractor::Options options;
+  options.only_permissions = true;
+
+  io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
+  text::Printer printer(&fout);
+  for (auto apk : args) {
+    auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_);
+    if (!loaded_apk) {
+      return 1;
+    }
+
+    ManifestExtractor extractor(loaded_apk.get(), options);
+    extractor.Dump(printer, diag_);
+  }
+
+  return 0;
+}
+
+} // namespace aapt
\ No newline at end of file
diff --git a/tools/aapt2/dump/DumpManifest.h b/tools/aapt2/dump/DumpManifest.h
new file mode 100644
index 0000000..a70be53
--- /dev/null
+++ b/tools/aapt2/dump/DumpManifest.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT2_DUMP_MANIFEST_H
+#define AAPT2_DUMP_MANIFEST_H
+
+#include <Diagnostics.h>
+#include <ValueVisitor.h>
+#include <io/ZipArchive.h>
+
+
+#include "cmd/Command.h"
+#include "process/IResourceTableConsumer.h"
+#include "text/Printer.h"
+#include "xml/XmlDom.h"
+
+namespace aapt {
+
+class DumpBadgingCommand : public Command {
+ public:
+  explicit DumpBadgingCommand(IDiagnostics* diag) : Command("badging"), diag_(diag) {
+    SetDescription("Print information extracted from the manifest of the APK.");
+    AddOptionalSwitch("--include-meta-data", "Include meta-data information.",
+                      &include_metadata_);
+  }
+
+  int Action(const std::vector<std::string>& args) override;
+
+ private:
+  IDiagnostics* diag_;
+  bool include_metadata_ = false;
+};
+
+class DumpPermissionsCommand : public Command {
+ public:
+  explicit DumpPermissionsCommand(IDiagnostics* diag) : Command("permissions"), diag_(diag) {
+    SetDescription("Print the permissions extracted from the manifest of the APK.");
+  }
+
+  int Action(const std::vector<std::string>& args) override;
+
+ private:
+  IDiagnostics* diag_;
+};
+
+}// namespace aapt
+
+#endif //AAPT2_DUMP_MANIFEST_H
\ No newline at end of file
diff --git a/tools/aapt2/io/FileStream_test.cpp b/tools/aapt2/io/FileStream_test.cpp
index c0eaa8e..7872738 100644
--- a/tools/aapt2/io/FileStream_test.cpp
+++ b/tools/aapt2/io/FileStream_test.cpp
@@ -41,46 +41,46 @@
   ASSERT_FALSE(in.HadError());
   EXPECT_THAT(in.ByteCount(), Eq(0u));
 
-  const char* buffer;
+  const void* buffer;
   size_t size;
-  ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size)) << in.GetError();
+  ASSERT_TRUE(in.Next(&buffer, &size)) << in.GetError();
   ASSERT_THAT(size, Eq(10u));
   ASSERT_THAT(buffer, NotNull());
   EXPECT_THAT(in.ByteCount(), Eq(10u));
-  EXPECT_THAT(StringPiece(buffer, size), Eq("this is a "));
+  EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("this is a "));
 
-  ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
+  ASSERT_TRUE(in.Next(&buffer, &size));
   ASSERT_THAT(size, Eq(10u));
   ASSERT_THAT(buffer, NotNull());
   EXPECT_THAT(in.ByteCount(), Eq(20u));
-  EXPECT_THAT(StringPiece(buffer, size), Eq("cool strin"));
+  EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("cool strin"));
 
   in.BackUp(5u);
   EXPECT_THAT(in.ByteCount(), Eq(15u));
 
-  ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
+  ASSERT_TRUE(in.Next(&buffer, &size));
   ASSERT_THAT(size, Eq(5u));
   ASSERT_THAT(buffer, NotNull());
   ASSERT_THAT(in.ByteCount(), Eq(20u));
-  EXPECT_THAT(StringPiece(buffer, size), Eq("strin"));
+  EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("strin"));
 
   // Backup 1 more than possible. Should clamp.
   in.BackUp(11u);
   EXPECT_THAT(in.ByteCount(), Eq(10u));
 
-  ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
+  ASSERT_TRUE(in.Next(&buffer, &size));
   ASSERT_THAT(size, Eq(10u));
   ASSERT_THAT(buffer, NotNull());
   ASSERT_THAT(in.ByteCount(), Eq(20u));
-  EXPECT_THAT(StringPiece(buffer, size), Eq("cool strin"));
+  EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("cool strin"));
 
-  ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
+  ASSERT_TRUE(in.Next(&buffer, &size));
   ASSERT_THAT(size, Eq(1u));
   ASSERT_THAT(buffer, NotNull());
   ASSERT_THAT(in.ByteCount(), Eq(21u));
-  EXPECT_THAT(StringPiece(buffer, size), Eq("g"));
+  EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("g"));
 
-  EXPECT_FALSE(in.Next(reinterpret_cast<const void**>(&buffer), &size));
+  EXPECT_FALSE(in.Next(&buffer, &size));
   EXPECT_FALSE(in.HadError());
 }
 
@@ -93,25 +93,25 @@
   ASSERT_FALSE(out.HadError());
   EXPECT_THAT(out.ByteCount(), Eq(0u));
 
-  char* buffer;
+  void* buffer;
   size_t size;
-  ASSERT_TRUE(out.Next(reinterpret_cast<void**>(&buffer), &size));
+  ASSERT_TRUE(out.Next(&buffer, &size));
   ASSERT_THAT(size, Eq(10u));
   ASSERT_THAT(buffer, NotNull());
   EXPECT_THAT(out.ByteCount(), Eq(10u));
-  memcpy(buffer, input.c_str(), size);
+  memcpy(reinterpret_cast<char*>(buffer), input.c_str(), size);
 
-  ASSERT_TRUE(out.Next(reinterpret_cast<void**>(&buffer), &size));
+  ASSERT_TRUE(out.Next(&buffer, &size));
   ASSERT_THAT(size, Eq(10u));
   ASSERT_THAT(buffer, NotNull());
   EXPECT_THAT(out.ByteCount(), Eq(20u));
-  memcpy(buffer, input.c_str() + 10u, size);
+  memcpy(reinterpret_cast<char*>(buffer), input.c_str() + 10u, size);
 
-  ASSERT_TRUE(out.Next(reinterpret_cast<void**>(&buffer), &size));
+  ASSERT_TRUE(out.Next(&buffer, &size));
   ASSERT_THAT(size, Eq(10u));
   ASSERT_THAT(buffer, NotNull());
   EXPECT_THAT(out.ByteCount(), Eq(30u));
-  buffer[0] = input[20u];
+  reinterpret_cast<char*>(buffer)[0] = input[20u];
   out.BackUp(size - 1);
   EXPECT_THAT(out.ByteCount(), Eq(21u));
 
diff --git a/tools/aapt2/io/Util.h b/tools/aapt2/io/Util.h
index b07fb53..5f978a8 100644
--- a/tools/aapt2/io/Util.h
+++ b/tools/aapt2/io/Util.h
@@ -20,6 +20,7 @@
 #include <string>
 
 #include "google/protobuf/message_lite.h"
+#include "google/protobuf/io/coded_stream.h"
 
 #include "format/Archive.h"
 #include "io/File.h"
@@ -122,6 +123,23 @@
   io::InputStream* in_;
 };
 
+class ProtoInputStreamReader {
+ public:
+  explicit ProtoInputStreamReader(io::InputStream* in) : in_(in) { }
+
+  /** Deserializes a MessageLite proto from the current position in the input stream.*/
+  template <typename T> bool ReadMessage(T *message_lite) {
+    ZeroCopyInputAdaptor adapter(in_);
+    google::protobuf::io::CodedInputStream coded_stream(&adapter);
+    coded_stream.SetTotalBytesLimit(std::numeric_limits<int32_t>::max(),
+                                    coded_stream.BytesUntilTotalBytesLimit());
+    return message_lite->ParseFromCodedStream(&coded_stream);
+  }
+
+ private:
+  io::InputStream* in_;
+};
+
 }  // namespace io
 }  // namespace aapt
 
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index c5c78d9..fa6538d 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -252,6 +252,7 @@
   xml::XmlNodeAction component_action;
   component_action.Action(RequiredNameIsJavaClassName);
   component_action["intent-filter"] = intent_filter_action;
+  component_action["preferred"] = intent_filter_action;
   component_action["meta-data"] = meta_data_action;
 
   // Manifest actions.
@@ -414,6 +415,8 @@
   application_action["provider"]["grant-uri-permission"];
   application_action["provider"]["path-permission"];
 
+  manifest_action["package"] = manifest_action;
+
   return true;
 }
 
diff --git a/tools/aapt2/split/TableSplitter.cpp b/tools/aapt2/split/TableSplitter.cpp
index e991743..b5c33062 100644
--- a/tools/aapt2/split/TableSplitter.cpp
+++ b/tools/aapt2/split/TableSplitter.cpp
@@ -154,6 +154,12 @@
 bool TableSplitter::VerifySplitConstraints(IAaptContext* context) {
   bool error = false;
   for (size_t i = 0; i < split_constraints_.size(); i++) {
+    if (split_constraints_[i].configs.size() == 0) {
+      // For now, treat this as a warning. We may consider aborting processing.
+      context->GetDiagnostics()->Warn(DiagMessage()
+                                       << "no configurations for constraint '"
+                                       << split_constraints_[i].name << "'");
+    }
     for (size_t j = i + 1; j < split_constraints_.size(); j++) {
       for (const ConfigDescription& config : split_constraints_[i].configs) {
         if (split_constraints_[j].configs.find(config) != split_constraints_[j].configs.end()) {
diff --git a/tools/aapt2/split/TableSplitter.h b/tools/aapt2/split/TableSplitter.h
index 6aec257..ed24bc39 100644
--- a/tools/aapt2/split/TableSplitter.h
+++ b/tools/aapt2/split/TableSplitter.h
@@ -30,6 +30,7 @@
 
 struct SplitConstraints {
   std::set<ConfigDescription> configs;
+  std::string name;
 };
 
 struct TableSplitterOptions {
diff --git a/tools/aapt2/test/Builders.h b/tools/aapt2/test/Builders.h
index fd5262a..be6e510 100644
--- a/tools/aapt2/test/Builders.h
+++ b/tools/aapt2/test/Builders.h
@@ -204,6 +204,112 @@
   configuration::PostProcessingConfiguration config_;
 };
 
+class ConfigDescriptionBuilder {
+ public:
+  ConfigDescriptionBuilder() = default;
+
+  ConfigDescriptionBuilder& setMcc(uint16_t mcc) {
+    config_.mcc = mcc;
+    return *this;
+  }
+  ConfigDescriptionBuilder& setMnc(uint16_t mnc) {
+    config_.mnc = mnc;
+    return *this;
+  }
+  ConfigDescriptionBuilder& setLanguage(uint16_t language) {
+    config_.language[0] = language >> 8;
+    config_.language[1] = language & 0xff;
+    return *this;
+  }
+  ConfigDescriptionBuilder& setCountry(uint16_t country) {
+    config_.country[0] = country >> 8;
+    config_.country[1] = country & 0xff;
+    return *this;
+  }
+  ConfigDescriptionBuilder& setOrientation(uint8_t orientation) {
+    config_.orientation = orientation;
+    return *this;
+  }
+  ConfigDescriptionBuilder& setTouchscreen(uint8_t touchscreen) {
+    config_.touchscreen = touchscreen;
+    return *this;
+  }
+  ConfigDescriptionBuilder& setDensity(uint16_t density) {
+    config_.density = density;
+    return *this;
+  }
+  ConfigDescriptionBuilder& setKeyboard(uint8_t keyboard) {
+    config_.keyboard = keyboard;
+    return *this;
+  }
+  ConfigDescriptionBuilder& setNavigation(uint8_t navigation) {
+    config_.navigation = navigation;
+    return *this;
+  }
+  ConfigDescriptionBuilder& setInputFlags(uint8_t inputFlags) {
+    config_.inputFlags = inputFlags;
+    return *this;
+  }
+  ConfigDescriptionBuilder& setInputPad0(uint8_t inputPad0) {
+    config_.inputPad0 = inputPad0;
+    return *this;
+  }
+  ConfigDescriptionBuilder& setScreenWidth(uint16_t screenWidth) {
+    config_.screenWidth = screenWidth;
+    return *this;
+  }
+  ConfigDescriptionBuilder& setScreenHeight(uint16_t screenHeight) {
+    config_.screenHeight = screenHeight;
+    return *this;
+  }
+  ConfigDescriptionBuilder& setSdkVersion(uint16_t sdkVersion) {
+    config_.sdkVersion = sdkVersion;
+    return *this;
+  }
+  ConfigDescriptionBuilder& setMinorVersion(uint16_t minorVersion) {
+    config_.minorVersion = minorVersion;
+    return *this;
+  }
+  ConfigDescriptionBuilder& setScreenLayout(uint8_t screenLayout) {
+    config_.screenLayout = screenLayout;
+    return *this;
+  }
+  ConfigDescriptionBuilder& setUiMode(uint8_t uiMode) {
+    config_.uiMode = uiMode;
+    return *this;
+  }
+  ConfigDescriptionBuilder& setSmallestScreenWidthDp(uint16_t smallestScreenWidthDp) {
+    config_.smallestScreenWidthDp = smallestScreenWidthDp;
+    return *this;
+  }
+  ConfigDescriptionBuilder& setScreenWidthDp(uint16_t screenWidthDp) {
+    config_.screenWidthDp = screenWidthDp;
+    return *this;
+  }
+  ConfigDescriptionBuilder& setScreenHeightDp(uint16_t screenHeightDp) {
+    config_.screenHeightDp = screenHeightDp;
+    return *this;
+  }
+  ConfigDescriptionBuilder& setScreenLayout2(uint8_t screenLayout2) {
+    config_.screenLayout2 = screenLayout2;
+    return *this;
+  }
+  ConfigDescriptionBuilder& setColorMode(uint8_t colorMode) {
+    config_.colorMode = colorMode;
+    return *this;
+  }
+  ConfigDescriptionBuilder& setScreenConfigPad2(uint16_t screenConfigPad2) {
+    config_.screenConfigPad2 = screenConfigPad2;
+    return *this;
+  }
+  ConfigDescription Build() {
+    return config_;
+  }
+
+ private:
+  ConfigDescription config_;
+};
+
 }  // namespace test
 }  // namespace aapt
 
diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp
index 7cd023b..73105e16 100644
--- a/tools/aapt2/util/Files.cpp
+++ b/tools/aapt2/util/Files.cpp
@@ -102,12 +102,25 @@
 #endif
 
 bool mkdirs(const std::string& path) {
-  constexpr const mode_t mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP;
+  #ifdef _WIN32
+  // Start after the drive path if present. Calling mkdir with only the drive will cause an error.
+  size_t current_pos = 1u;
+  if (path.size() >= 3 && path[1] == ':' &&
+        (path[2] == '\\' || path[2] == '/')) {
+    current_pos = 3u;
+  }
+ #else
   // Start after the first character so that we don't consume the root '/'.
   // This is safe to do with unicode because '/' will never match with a continuation character.
   size_t current_pos = 1u;
+ #endif
+  constexpr const mode_t mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP;
   while ((current_pos = path.find(sDirSep, current_pos)) != std::string::npos) {
     std::string parent_path = path.substr(0, current_pos);
+    if (parent_path.empty()) {
+      continue;
+    }
+
     int result = ::android::base::utf8::mkdir(parent_path.c_str(), mode);
     if (result < 0 && errno != EEXIST) {
       return false;
diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp
index 9bef54e5..59b7fff 100644
--- a/tools/aapt2/util/Util.cpp
+++ b/tools/aapt2/util/Util.cpp
@@ -322,11 +322,11 @@
   output.reserve(modified_size);
   for (size_t i = 0; i < size; i++) {
     if (((uint8_t) utf8[i] >> 4) == 0xF) {
-      auto codepoint = (char32_t) utf32_from_utf8_at(utf8.data(), size, i, nullptr);
+      int32_t codepoint = utf32_from_utf8_at(utf8.data(), size, i, nullptr);
 
       // Calculate the high and low surrogates as UTF-16 would
-      char32_t high = ((codepoint - 0x10000) / 0x400) + 0xD800;
-      char32_t low = ((codepoint - 0x10000) % 0x400) + 0xDC00;
+      int32_t high = ((codepoint - 0x10000) / 0x400) + 0xD800;
+      int32_t low = ((codepoint - 0x10000) % 0x400) + 0xDC00;
 
       // Encode each surrogate in UTF-8
       output.push_back((char) (0xE4 | ((high >> 12) & 0xF)));
@@ -344,6 +344,60 @@
   return output;
 }
 
+std::string ModifiedUtf8ToUtf8(const std::string& modified_utf8) {
+  // The UTF-8 representation will have a byte length less than or equal to the Modified UTF-8
+  // representation.
+  std::string output;
+  output.reserve(modified_utf8.size());
+
+  size_t index = 0;
+  const size_t modified_size = modified_utf8.size();
+  while (index < modified_size) {
+    size_t next_index;
+    int32_t high_surrogate = utf32_from_utf8_at(modified_utf8.data(), modified_size, index,
+                                                &next_index);
+    if (high_surrogate < 0) {
+      return {};
+    }
+
+    // Check that the first codepoint is within the high surrogate range
+    if (high_surrogate >= 0xD800 && high_surrogate <= 0xDB7F) {
+      int32_t low_surrogate = utf32_from_utf8_at(modified_utf8.data(), modified_size, next_index,
+                                                 &next_index);
+      if (low_surrogate < 0) {
+        return {};
+      }
+
+      // Check that the second codepoint is within the low surrogate range
+      if (low_surrogate >= 0xDC00 && low_surrogate <= 0xDFFF) {
+        const char32_t codepoint = (char32_t) (((high_surrogate - 0xD800) * 0x400)
+            + (low_surrogate - 0xDC00) + 0x10000);
+
+        // The decoded codepoint should represent a 4 byte, UTF-8 character
+        const size_t utf8_length = (size_t) utf32_to_utf8_length(&codepoint, 1);
+        if (utf8_length != 4) {
+          return {};
+        }
+
+        // Encode the UTF-8 representation of the codepoint into the string
+        char* start = &output[output.size()];
+        output.resize(output.size() + utf8_length);
+        utf32_to_utf8((char32_t*) &codepoint, 1, start, utf8_length + 1);
+
+        index = next_index;
+        continue;
+      }
+    }
+
+    // Append non-surrogate pairs to the output string
+    for (size_t i = index; i < next_index; i++) {
+      output.push_back(modified_utf8[i]);
+    }
+    index = next_index;
+  }
+  return output;
+}
+
 std::u16string Utf8ToUtf16(const StringPiece& utf8) {
   ssize_t utf16_length = utf8_to_utf16_length(
       reinterpret_cast<const uint8_t*>(utf8.data()), utf8.length());
@@ -469,7 +523,7 @@
   size_t len;
   const char* str = pool.string8At(idx, &len);
   if (str != nullptr) {
-    return std::string(str, len);
+    return ModifiedUtf8ToUtf8(std::string(str, len));
   }
   return Utf16ToUtf8(GetString16(pool, idx));
 }
diff --git a/tools/aapt2/util/Util.h b/tools/aapt2/util/Util.h
index 36b7333..c6e8e6e 100644
--- a/tools/aapt2/util/Util.h
+++ b/tools/aapt2/util/Util.h
@@ -199,6 +199,7 @@
 
 // Converts a UTF8 string into Modified UTF8
 std::string Utf8ToModifiedUtf8(const std::string& utf8);
+std::string ModifiedUtf8ToUtf8(const std::string& modified_utf8);
 
 // Converts a UTF8 string to a UTF16 string.
 std::u16string Utf8ToUtf16(const android::StringPiece& utf8);
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index 018e9c9..934847f 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -697,8 +697,8 @@
         "android.provider",
         ["android.content","android.graphics.drawable"],
         "android.database",
-        "android.graphics",
         "android.text",
+        "android.graphics",
         "android.os",
         "android.util"
     ]
diff --git a/tools/hiddenapi/generate_hiddenapi_lists.py b/tools/hiddenapi/generate_hiddenapi_lists.py
index 6c46e67..fdc800b 100755
--- a/tools/hiddenapi/generate_hiddenapi_lists.py
+++ b/tools/hiddenapi/generate_hiddenapi_lists.py
@@ -212,8 +212,8 @@
     move_from_files(args.input_greylists, uncategorized, light_greylist)
     move_from_files(args.input_blacklists, uncategorized, blacklist)
 
-    # Iterate over all uncategorized members and move serialization API to light greylist.
-    move_serialization(uncategorized, light_greylist)
+    # Iterate over all uncategorized members and move serialization API to whitelist.
+    move_serialization(uncategorized, whitelist)
 
     # Extract package names of members from whitelist and light greylist, which
     # are assumed to have been finalized at this point. Assign all uncategorized
diff --git a/tools/hiddenapi/generate_hiddenapi_lists_test.py b/tools/hiddenapi/generate_hiddenapi_lists_test.py
index 8f79318..4716241 100755
--- a/tools/hiddenapi/generate_hiddenapi_lists_test.py
+++ b/tools/hiddenapi/generate_hiddenapi_lists_test.py
@@ -85,5 +85,23 @@
         self.assertEqual(
             dst, set([ "Lfoo/bar/ClassA;->abc()J", "Lfoo/bar/ClassA;->def()J" ]))
 
+    def test_move_serialization(self):
+        # All the entries should be moved apart from the last one
+        src = set([ "Lfoo/bar/ClassA;->readObject(Ljava/io/ObjectInputStream;)V",
+                    "Lfoo/bar/ClassA;->readObjectNoData()V",
+                    "Lfoo/bar/ClassA;->readResolve()Ljava/lang/Object;",
+                    "Lfoo/bar/ClassA;->serialVersionUID:J",
+                    "Lfoo/bar/ClassA;->serialPersistentFields:[Ljava/io/ObjectStreamField;",
+                    "Lfoo/bar/ClassA;->writeObject(Ljava/io/ObjectOutputStream;)V",
+                    "Lfoo/bar/ClassA;->writeReplace()Ljava/lang/Object;",
+                    # Should not be moved as signature does not match
+                    "Lfoo/bar/ClassA;->readObject(Ljava/io/ObjectInputStream;)I"])
+        expectedToMove = len(src) - 1
+        dst = set()
+        packages = set([ "Lfoo/bar/" ])
+        move_serialization(src, dst)
+        self.assertEqual(len(src), 1)
+        self.assertEqual(len(dst), expectedToMove)
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/tools/hiddenapi/sort_api.sh b/tools/hiddenapi/sort_api.sh
index bdcc807..76a2f2d 100755
--- a/tools/hiddenapi/sort_api.sh
+++ b/tools/hiddenapi/sort_api.sh
@@ -12,8 +12,8 @@
 # Sort
 IFS=$'\n'
 # Stash away comments
-C=( $(grep -E '^#' <<< "${A[*]}") )
-A=( $(grep -v -E '^#' <<< "${A[*]}") )
+C=( $(grep -E '^#' <<< "${A[*]}" || :) )
+A=( $(grep -v -E '^#' <<< "${A[*]}" || :) )
 # Sort entries
 A=( $(LC_COLLATE=C sort -f <<< "${A[*]}") )
 A=( $(uniq <<< "${A[*]}") )
diff --git a/tools/incident_section_gen/main.cpp b/tools/incident_section_gen/main.cpp
index 639f980..0cf1046 100644
--- a/tools/incident_section_gen/main.cpp
+++ b/tools/incident_section_gen/main.cpp
@@ -138,7 +138,7 @@
     size_t base = 0;
     size_t found;
     while (true) {
-        found = args.find_first_of(" ", base);
+        found = args.find_first_of(' ', base);
         if (found != base) {
             string arg = args.substr(base, found - base);
             printf(" \"%s\",", arg.c_str());
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index ce8d71d..58c1300 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -332,9 +332,10 @@
     public String preSharedKey;
 
     /**
-     * Up to four WEP keys. Either an ASCII string enclosed in double
-     * quotation marks (e.g., {@code "abcdef"}) or a string
-     * of hex digits (e.g., {@code 0102030405}).
+     * 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
+     * (e.g., {@code ""}).
      * <p/>
      * When the value of one of these keys is read, the actual key is
      * not returned, just a "*" if the key has a value, or the null
diff --git a/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java b/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java
index bb02dec..b4dfac6 100644
--- a/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java
+++ b/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java
@@ -127,7 +127,7 @@
     public static final int OSU_STATUS_SERVICE_PROVIDER_VERIFIED = 5;
 
     /**
-     * The status code for provisioning flow to indicate starting the SOAP exchange.
+     * The status code for provisioning flow to indicate starting the first SOAP exchange.
      */
     public static final int OSU_STATUS_INIT_SOAP_EXCHANGE = 6;
 
@@ -142,6 +142,11 @@
     public static final int OSU_STATUS_REDIRECT_RESPONSE_RECEIVED = 8;
 
     /**
+     * The status code for provisioning flow to indicate starting the second SOAP exchange.
+     */
+    public static final int OSU_STATUS_SECOND_SOAP_EXCHANGE = 9;
+
+    /**
      * Provisioning status for OSU failure
      *
      * @param status indicates error condition
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 57f3973..5a4c898 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -30,6 +30,7 @@
 import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceInfo;
 import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceResponse;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -488,7 +489,7 @@
      * @hide - hide this because it takes in a parameter of type IWifiP2pManager, which
      * is a system private class.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public WifiP2pManager(IWifiP2pManager service) {
         mService = service;
     }